Hacker News new | past | comments | ask | show | jobs | submit login
HTML and CSS techniques to reduce your JavaScript (perfplanet.com)
571 points by ______- on June 3, 2021 | hide | past | favorite | 133 comments

I’m not surprised but a little disappointed that most of the older techniques aren’t mentioned:

- checkbox/radio inputs can be used to toggle state with `:checked ~ .foo` selectors

- `:focus` (and now `:focus-within`, and `:active` though it’s less useful) can be used similarly, but also allow child selection [Edit to add: `tabindex="-1"` makes anything focusable with a pointer input, but doesn’t capture keyboard tab or iteration with assistive tools]

- `:target` can be used similarly, paired with fragment links [Edit to add: but beware history entries, this can be a poor UX]

- `<label>` can be used to not only set those states but also trigger scrolls (including within `scroll-snap` parents) without creating navigation history entries

- the `attr()` function can be used to reference server-dynamic HTML data for display with `content` in pseudo-elements

- I have to assume CSS animations are adopted widely enough that people aren’t using JS for that where it isn’t needed; but you can also use declarative, even interactive, animations in SVG

- speaking of which, inline SVG (even `<use>` references) are part of the CSS cascade, and you can change any CSS-addressable property with `currentColor`

- and you can nest HTML in SVG with `<foreignObject>` if you want to use SVG techniques in HTML

- probably not worth mentioning but in case you don’t know... if you miss table layouts, you can use them with `display` on basically anything; if you want table semantics without tabular rendering you can override `display` as well

Alllllll of that being said, if you use these techniques check your stuff with assistive technologies!

:focus-within is a favourite of mine since it is one of the few CSS selectors where child element state is significant. Thus it is very nice for drop-downs. It also works with CSS transitions, so my pure CSS drop-downs have a 150ms easing in & out (tip: transition the visibility property, since display:none can't be delayed).

There is another, however. An element whose state depends on that of other elements, and it's even more general. A form element moves between :valid and :invalid based on its inputs, allowing us to use form:{in}valid with any of the descendant, child, sibling or adjacent combinators. A hidden required checkbox is sufficient. Radio inputs work too (tip: you can clear radios back to :invalid with an input type="reset").

The really, truly monstrous part of this, however, is that the associated input doesn't even have to be a child of the form. Using the form attribute (i.e., <input form="whatever">) means they can be anywhere on the page, and they can themselves be hidden and targeted from somewhere else on the page again, with a <label> element.

I once documented the horrifying potential of this in a company wiki, along with a lovely modal slideover that was wrapped in a <form> element and transitioned to visible based on form:valid via a hidden required radio button, and whose backdrop was a reset button, and this was rightly labelled NSFW and banned by popular acclaim from ever appearing in our HTML.

Oh my gosh. I’ve read this comment over and over, and didn’t “get it” until it finally clicked just now. You found a way to use form validity as a parent selector! Monstrous for sure, but fucking brilliant and I’m ashamed I haven’t thought of it as I’ve been trying to justify... all manner of things to claw sibling selectors back from things I want to use but div/custom-element wrap in ways I can’t abide.

Try imagining the possibilities when using validation-capable inputs other that checkboxes and radios, too. How about a range slider, or a text input with a validation regex...

For further inspiration, I recommend reading the entirety of the HTML Living Standard and the current CSS Snapshot about once a year. I'm currently excited about the opportunities for [open], particularly with the <details> and <dialog> elements.

My biggest disappoints of the year are with <datalist>, unfortunately, which is so mysteriously half-baked it's practically worthless; followed by Webkit dragging its heels over <dialog> support and customized built-in element support.

The form/valid one is very interesting but I'm not sure I completely follow, especially the last example. Would you be able to post a Codepen?

Since it just finally made sense to me... it’s basically the checkbox hack but without a sibling structure requirement. Given markup like this:

    <form id="foo"></form>
    <div class="target">...</div>
    <div class="doesnt-matter">
        <input type="checkbox" form="foo" required>
You can target `.target` with:

    #foo:invalid ~ .target
Because the checkbox is required/unchecked. (And the inverse if it’s checked using `:valid`.)

Ok, this is a great hack - but what would one practically use this for ? I mean the standard checkbox hack works too right ? Or is there some place where this technique excels ?

There are two bonus capabilities from using the form:valid hack:

1. The input element(s) can now be anywhere on the page. You can, for example, use adjacency to style a control button, without torturing your HTML to squeeze the button into being a sibling of whatever it's activating.

2. You can use form:valid as a parent selector i.e. as a wrapper element. You couldn't use an input:checked as a parent selector because the <input> element's content model is "nothing" i.e. there are no child elements under an <input>, but you sure can with a <form>. The result is less brittle to code-rot.

This is extremely freeing and allows you to use, for example, a :checked adjacency for styling an activation button and a wrapper element (a form:valid) for the large complex component (modal? drop-down? slideover? video content?) that it activates. Heck, it can even be an iframe. Here's the bones of an example:


There are two downsides:

1. Behaviour of some elements is different inside a <form>. Most obviously, don't nest a <form> inside with the same scope.

2. Your HTML maybe become a mess of scattered <form>, <input>, and <label> elements that many other developers will look at and say "WTF was this person thinking" and "what does this button do?"

I would use it where I don’t have full control over the document structure (for example where my checkbox can’t sibling select because something third party wraps it in a div).

I'm assuming the input is toggled via js (or server rendered html) - and the selector is used for cascading "state" into the html?

Done. I've posted a sample usage, it's in a reply to a comment a bit further down.

> toggle state with `:checked ~ .foo` selectors

I loved this when I first learned it but was convinced by some accessibility-minded people that it usually doesn’t accurately convey the state to assistive technologies. Instead, use a <button> with an appropriate ARIA attribute conveying a state (pressed, expanded, etc.) that’s toggled by JavaScript. Or use <details> <summary> elements if it’s a disclosure widget.

Yeah, they lied to you. The trouble with ARIA is that it relies, fundamentally, on the assumption that everything's a RIA (the hint is in the name). This assumption is bollocks.

A typical failure scenario is toggles in forms, that appeared to have been set by button-press, but have only changed cosmetically. The silent errors that creep in this way are painful to unravel. Relying on input element state avoids not merely the tail wagging the dog, but the tail wagging only itself because TypeError: dog is not an object.

When overused, or used in a cargo-cult fashion, ARIA is also notorious for making pages less accessible, and unfortunately this is frequently the case.

If you want to build accessible pages, then write simple and semantic HTML. Out of the box this is likely to be fairly accessible from the go. Then annotate using the minimum of JS to set the minimum of ARIA attributes that clearly improve accessibility, and if someone's relying on ARIA then you can, by definition, assume that JS is available, since it is (I'll reiterate this) right there in the name, and what's more if it it's broken or unavailable, then your fallback plain-old-HTML retains some semblance of utility and accessibility for assisted and non-assisted visitors alike.

The path through the swamp doesn't have to be smothering it in concrete.

> annotate using the minimum of JS to set the minimum of ARIA attributes that clearly improve accessibility

Yes, like aria-expanded="true" on a <button> that opens a custom disclosure widget instead of using the CSS-only :checked ~ .foo hack I was responding to. The actual hiding/revealing of the related content can still be done with CSS alone using [aria-expanded="true"].

Here's a bunch of checkbox hack examples [0]. The custom radio buttons and checkboxes and the push toggles are fine (the use-case is fine, I didn't closely examine everything about the implementations), the rest should be done some other way that probably involves buttons with JavaScript.

[0] https://css-tricks.com/the-checkbox-hack/

Custom radio buttons and checkboxes are remarkably easy if you style the <input> it self using `appearance: none`. With multiple background images and masks there is really no need for a complicated sibling selectors and <label> setup:

      <input type="checkbox">
      <span class="label">Some label</span>

    input[type="checkbox"] {
      appearance: none;
      /* ... */

    input[type="checkbox"]:checked { /* ... */ }
    input[type="checkbox"]:indeterminate { /* ... */ }
    input[type="checkbox"]:disabled { /* ... */ }

That's good to keep in mind. No IE support for `appearance` but it can be used in such a way that it's just a more ordinary input in that browser.

There are still more things you can do within a label. This is a good article on improving methods of visually hiding the actual inputs.


Also: almost all of these are actively in use on my personal site, they’re not just stuff I mention academically. They’re great for places you might progressively enhance with JS but want to provide reasonable no-JS fallbacks.

I'm new to getting my designs working well with assistive tools. What do you use for testing and what are the prominent tools that should be targeted?

I would recommend getting comfortable using the built-in screen readers on your own devices (VoiceOver, Narrator, etc). Lots of people use those same tools. You'll probably just want to mute the screen reader and use the developer option to display what's being announced on screen as text.

Get comfortable navigating web pages using the various functionalities available (the ability to scan only headlines, for example).

I also open the accessibility tab in the web inspector in Chrome or Firefox to see the accessibility tree, which is like a simplified version of the DOM tree that gets exposed to assistive technologies.

Admittedly I have a better track record saying than doing. So I’ll double down on that and repeat what all of the a11y advocates I follow say:

- you want to at least test with JAWS, NVDA and VoiceOver

- automated tooling isn’t great and you probably need to manually verify things

- axe does help spot problems just don’t rely on it completely

As a linux user I do most of my assistive technology testing with Orcas. Do you have any insight into that? Do many assistive technology users use Orcas? Is Orcas behavior significantly different from the more popular once?

In the last WebAIM Screen Reader survey [0], if anyone answered they primarily use Orca, they got lumped into "Other"; out of over 1,000 respondents, 7 primarily use Chromevox so the Orca number must be lower than that. If some use Orca sometimes, they must have been less than 1% of the respondents and got lumped into Other for that question as well.

That doesn't mean that Orca doesn't do a good job or that it works very differently than other screen readers. The A11ySupport site [1] does have some data on Orca's support for specific code. For instance, it fully supports the aria-expanded attribute but has no support for description list elements.

If you have an iOS or Android device, using their built-in screen readers might be more instructive.

[0] https://webaim.org/projects/screenreadersurvey8/ [1] https://a11ysupport.io/

No, I wish I had insight here but I don't. I'm sorry I can't be any more help.

> you want to at least test with JAWS, NVDA and VoiceOver

It depends on what the stakes are but if you’re consistently confirming things work with just one screen reader, that makes most of the difference.

NVDA with Firefox or Chrome is probably the best to test with; it’s free, probably the most common choice now, and it has a lot in common with JAWS. But if testing with Windows is inconvenient, testing VoiceOver with Safari for Mac is still very useful, in part because it’s very similar to VoiceOver on iOS.

Thanks for the tips. I'll check those out.

The most simple way to test accessibility is to only use a keyboard. Use tab ir shift-tab to switch between elements. Tab only browses through links and form elements. Use enter to follow links or buttons.

Simple things like 'outline' on focused or activated elements are easy things to pick up. Elements that are changed by JavaScript should not only change on a mouseclick or touch, but also on pressing Enter or ESC.

One popular case for :checked JavaScriptless visual state is popups of various kinds; these days, many of those can be done with <details>, which is normally semantically better out of the box and generally equally capable (even down to things like “click anywhere outside and it closes” via some full-viewport ::before, on the summary rather than label in this instance).

I‘ve found that SVG animations seem to be kind of slow, especially compared to CSS animations. My suspicion is that specific browsers don’t optimize them in the same way.

CSS animation are usually done with the use of the transform propertie. The transform propertie does not trigger painting, and then can be done with the help of the GPU.


Is there a good blog post about all those techniques you listed, or some collection? I would like to read more about it.

Something to keep in mind about using checkboxs and radios to toggle state changes, CSS tricks in general is that depending on what you're doing they're often not fully accessible. To fully support keyboard input and aria attributes like `aria-expanded` you often need to use JavaScript.

To fully support keyboard input...you often need to use JavaScript.

This seems 100% backward. What happened to tabindex? My experience has been that HTML+CSS (I wouldn't even call most of these "hacks", they are normal intended features of CSS) is much more likely to be navigable by keyboard than anything using JS.

Does anyone know if changing the display type of table elements (table, tr, td, etc.) to `block` or `flex` affect accessibility in any way? I would hope that the semantic structure of the tags would override changes on the styling level, but never been able to find a solid answer.

> checkbox/radio inputs can be used to toggle state with `:checked ~ .foo` selectors

What kind of state do you mean? Could you give an example?

An accordion widget is simply a series of radio button followed by div. You can see this in action at amazon.com in a product page with multiple purchase options, the buy button will have a radio with multiple options, it's just a radio button. An accordion that allows multiple open panes is a series of checkbox followed by div. More advanced, you can create a flashcard app by allotting two checkboxes per card. I used this technique around 3 years ago when I was studying kanji: http://sokogakuen.framba.ch

The pattern is:

<label> <input class”real-check” type=checkbox /> <span class”fake-check”/> <strong>this is the text label</strong> </label>

- visually hide the checkbox - use a selector like “.real-check:checked + .fake-check and draw whatever you want in the fake check. - the fake check and the text label are both inside the label element. Interacting with them will toggle the check box.

Here's a simple example, toggles for checkbox inputs. https://play.tailwindcss.com/BvQpg9QWEe

>if you miss table layouts, you can use them with `display` on basically anything

except not really because there's no CSS equivalent for rowspan/colspan. wish they would add this, it'd also be useful for making tables responsive.

Thanks for the attr tip though, somehow that one had completely slipped by me!

Sure there is, the grid-row and grid-column CSS properties


sure, but if I have an actual table with tabular data, it would be nice to be able to just hide a row and adjust colspan in css as well as necessary. it's much less of a problem than it used to be these days, since grid is very well supported now, but still kind of annoying to rebuild the entire table into a grid.

If you have an actual table with tabular data then your should be using an HTML table. That's what it's for.

yes and if i want to make it responsive i can't change the colspan/rowspan via css. that was my point.

You can! CSS Grid works just fine with <table> and its related elements. In fact Grid is overkill here, you can span multiple rows or columns using flexbox alone. You don't need to "rebuild" anything, use the same markup.

You couldn't control colspan/rowspan with CSS before, only HTML, which isn't responsive. (Ignoring the `column-span` property which isn't very flexible.)

I'm afraid we are still talking past one another. When I said "rebuild", what i meant was that I have to rebuild the table layout in css using grid to make it responsive. If they added a css equivalent of colspan/rowspan for table-layouts, it would be much easier to do simple tweaks to tables in css. it's not the end of the world that it's not possible, but it's already part of the layout engine so it wouldn't be hard to add. (and the column-span property is unrelated to tables)

We aren't, you need to be more specific.

> I have to rebuild the table layout

The "layout" meaning the visual appearance, or the markup?

There IS a "css equivalent of colspan/rowspan for table-layouts," put another way--a way to make a column or row (<td> or <tr>) appear to span multiple columns or rows. It can be achieved with flexbox or with CSS grid.

You don't need to change anything about the markup (HTML) to make this work.

> to make it responsive

"Responsive" as in "responds to the size of the viewport?" The colspan and rowspan HTML attributes do not do that. They have the same value regardless of the size of the viewport. CSS (with media queries) can respond.

> the column-span property is unrelated to tables

Incorrect, it is certainly related, and works there just fine (along with other in-flow block-level elements).

layout meaning i have to change the display type from table/table-row/table-cell to something else to recreate the way the table is structured. if there was a colspan/rowspan equivalent, i would not have to do this, and would the process would be much simpler. Yes, I know there are workarounds using flexbox, grid, etc. but as I've said before, it would be nice if i didn't have to reconstruct the whole thing in css just becuase there is no rowspan/colspan for table-layouts in css.

there is no equivalent of colspan/rowspan in css, as in not some convoluted workaround but doing exactly the same thing only via css instead of a html attribute. I don't really think I've been that unclear about this being what I want to be added. I was not talking about changing the html, but turning a table into a grid is more than just doing table {display:grid;}, you have to rebuild the whole structure, i.e. layout of the table using css. if i could use rowspan (as in actual literal rowspan not some other workaround), i would not have to do this.

yes responsive as in hide one or multiple rows of table cells on some screen resolutions to make things fit better. as I've previously said.

>Incorrect, it is certainly related, and works there just fine (along with other in-flow block-level elements).

it does not manipulate the amount of table rows a table-cell-display element takes up.

> doing exactly the same thing only via css instead of a html attribute

Yes! What's wrong with this approach? We have a lot of old HTML attributes that were used for styling that have been replaced by CSS.

> Yes, I know there are workarounds using flexbox, grid, etc

It's not a "workaround!" You're controlling the appearance using the styling language. What's wrong with this example?


> "responsive" as in hide rows of table cells on some resolutions to make things fit better

HTML attributes (like colspan) don't do this! CSS does.

> it does not manipulate the amount of table rows a table-cell-display element takes up

I know, I mentioned it before :) it's related though.

With HTML attributes the layout is tied to your markup. Like you said it's more than table {display:grid;} but is adding .colspan-2 a lot more cruft than adding [colspan=2]?

i feel like you are being willfully obtuse at this point.

All I want is two new css properties that mirror the behaviour of the colspan/rowspan html tag attributes. for things that are display:table-cell; (i.e. <td> tags). So that you can do light table manipulation without having to use grid or flexbox, which adds extra cruft that would be made redundant in situations where you want to do something very simple like hide a row.

One last time, i understand this is possible with a whole bunch of css to recreate the entire structure of the table using grid, but if we had these two css properties, you would not need to do all this. it would be more convenient.

If you still do not understand what I was trying to say, I'm sorry, I give up. This conversation has started to genuinely frustrate me at this point.

I'm currently trying to do as much as possible (without crazy hacks) in HTML / CSS alone, just because it's easier. Things like "position: sticky" are easier than anything JS could do.

if I may recommend my own library:


it extends the expressive power of HTML as a hypertext and allows you to do quite a bit more within the hypertext paradigm.

Like the parent I am trying to DIY most things on my personal projects. Standard library for everything except the database driver and… htmx ;)

Thank you!

Wow, this looks bloody brilliant. I’ve only recently begun feeling more “comfortable” writing JS on the fly for frontend development (previous roles were nearly all backend-centric), but one big issue I’m facing is managing the ever-growing ecosystem in a way to minimize complexities in a timely and efficient manner.

HTMX seems as though it will catalyze those efforts.

Wow thanks! I am definitely checking this out.

HTMX + TailwindCSS, so almost everything client-side is in HTML. And I use FreeMarker macros to generate the HTML components.

Wow, that's impressively cool ! Well done

htmx is great. Thank you for making it.

It’s also easier to debug, because state is so minimal and visible


Is there any good way to see why an element is a certain size? I often end up digging back and forth through children and parents and wanting to tear my hair out.

It's easy to see computed CSS properties and which selectors they come from (and what the order of specificity is that caused those properties to take effect)

Given the properties, I personally find sizes to be pretty predictable based on the rules of block or flex sizing

I'm talking about sizes that aren't coming from properties in that specific element. I can see that it's height 20 and I can see that it's not set directly, but how do I know if it's coming from the parent element or a child element, and for the latter how do I know which children/grandchildren/greatgrandchildren are causing it to be that size? And every one of those elements has 100 rules applied because it's a mess I didn't create, so brute force searching is a giant pain.

If it makes you feel any better, I must disagree with brundolf here and confirm that figuring out "which of these 1,500 DOM elements is the reason that between 321 to 334px width one of my container divs simply refuses to stay within screen boundaries" can be absolutely maddening and I have no idea how one would ease that process.

Element sizing in CSS is anything but straight forward, especially as there are loads of non obvious rules applied to elements like text inputs etc

But maybe I am just not as good at CSS as I thought :)

I'm also talking about sizes that aren't hardcoded. I don't really know what to tell you except that in my experience the rules governing the sizing of CSS elements don't tend to be very complicated. If you're in a default (block/inline) context, and no width or height is set, then if it's display: block it will be the full width of its parent and its height will be determined by its content. If it's inline or inline-block, its width will also be determined by its content. Flex contexts have their own rules that are a bit more complicated but remain very predictable once you learn them. Etc.

Generally, nearly every element's size comes down to some combination of:

1) Explicit width/height properties (and padding/margin)

2) Special layout mechanisms like filebox or grid

3) The element's contents

4) Its direct parent's dimensions

That's pretty much it. There's really no case I can think of where a grandparent directly drives an element's size (it may drive the parent's size which drives the child's size, but the reach at each individual stage remains short)

I tried to recreate my original full set of grievances, but firefox has changed the CSS around too much.

But I can still go with this:

I inspect the tab toolbar. I pick a tab and look at the contents of the div. Just inside the actual tab div is a "stack" element, whose width is being set to the size of its contents right now.

The stack is size 50.5x44, and it's display:grid.

It has two visible children. Both of them are 50.5x44, and are display: -moz-box.

I can tell from deep inspection and trial and error that one of those children is setting the size, and the other child is inheriting the size.

But if I don't want to dig around every single sub-div, what can I do to figure out which one is which?

They look the same in the layout inspector, and neither of them has any computed properties relative to width.

For bonus difficulty: If the parent div of the "stack" element tries to grow wider than the stack, the stack will grow to match its width, and the child divs of the stack will also grow to match it. All without any computed properties changing, or the layout inspector noting that anything is different.

So the size of the "stack" element could be set by either its parent or one of its children and I have no idea how to figure out which one except by experimentation. This is not a very pleasant experience.

Ideally, I could get a list of every element competing to set the width of a div, and which one(s) are winning. Less ideally, I could see just which element(s) are currently responsible for the size of a div. But as far as I can tell there's nothing, and I have to blindly search every other related element that has a suspiciously similar size.

Not only easier, but more performant. You don't end up with one element lagging behind as you scroll.

I was vaguely aware of several of these, but hadn't thought to use them in the ways the author proposes.

The gallery with horizontal snap scrolling, the use of smooth scrolling to jump between anchors and even clamp are all quite cool.

I also had no idea that's how sticky worked!

There's a limitation to `position:sticky;` though, which is that it will not work inside of ANY parent that's `overflow:auto` or `overflow:hidden`. I hope this gets addressed in a future version of the spec one day. Gtihub issue: https://github.com/w3c/csswg-drafts/issues/865

The biggest issue that happens to me is that I'll have a large data table where I want `overflow-x:auto` with a sticky header, and this is just impossible without Javascript. Of course, the UX of such a table is not ideal, but sometimes nothing will substitute for a large data table when you have a lot of data that goes into a table and people want to see it.

The thead isn't a child of tbody anyway; you can just make tbody scrollable for this, no?

Edit oh I missed the "x" there, I see.

The repeated "All browsers except Internet Explorer" with regard to support is exactly why a lot of these solutions are in javascript still for a lot of sites.

I don't believe that's a valid excuse in 2021. In 2017? Sure -- maybe. Even complete luddites don't use IE anymore because it hasn't been the default browser for many, many years.

While I agree there ARE some industries that have to support stupid old versions (eg government websites), any other product managers that think they'll be losing business by not supporting IE are misguided.

IE11 is officially supported for another year. IE compatibility mode is supported in Edge until 2029. Large organisations move very slowly.


Yeah, from personal experience any time I or anybody else tries to argue that supporting IE isn’t worth it any more, a PM will pull out traffic statistics and say ‘see, x% is still on IE, we can’t not support them’

Soon you'll be able to respond that even Microsoft is dropping support for IE. The IE application itself is reaching end of life on June 15th, 2022 [1] but Microsoft's own products will no longer support IE later this year in August [2].

[1] https://techcommunity.microsoft.com/t5/windows-it-pro-blog/i...

[2] https://docs.microsoft.com/en-us/lifecycle/announcements/int...

> a PM will pull out traffic statistics and say ‘see, x% is still on IE, we can’t not support them’

Sure, which can be countered with: "no problem, it will add 30% to the estimate".

Unless the % is significant (over 10%), it's not worth the effort.

Yep, that's exactly why I keep pushing to drop support. I am as interested as the PM in implementing a feature as efficiently as possible, and when I have to cadge together a js solution for something that's in CSS or, worse, cadge together IE-specific CSS overrides (truth be told, I have to do this for Safari often too), it automatically increases the estimation.

> truth be told, I have to do this for Safari often too

One day Safari will enable smooth scroll.

You then respond with “is x% worth y% longer time to market for new features, and n milliseconds longer load time for users on other browsers?”

Also don’t forget to check actual conversion and other important metrics for different browsers, not only number of visits.

according to caniuse it's less than a percent now. of course mileage may vary.

Right, like I noted elsewhere some industries have higher IE traffic, proportionally speaking

It used to be that many companies were stuck with IE because they bought complex products that only support IE (and an older version of IE at that) to manage their business with. Fortunately a lot of the worst of that stuff has gone away. But it's still out there (though in many cases the employees use IE only to talk to BogusLegacyProduct and use Chrome for everything else).

As an example, a school website I run support for on and off, and have done so for a number of years, still receives 18% of its traffic from IE8.

a bunch of school computers running XP? Or maybe the principal still runs xp and only 4 other people visit the site

No, in point of fact most of those 18% are parents at home running Windows XP. The entire school runs on Windows 10, as the cursing from the server room will tell you on a regular basis.

And the school site has quite an active userbase - students upload assignments via it, parents can live-view all gradings and remarks (and regularly use it), and staff generally access their email via it instead of a client.

interesting, i guess it must be people who almost don't have an internet presence at all beyond school. since in ie8, nothing works at this point (i imagine their kids might have their own computers). hell, a huge swath of https sites just flat out won't work in XP as i understand (e.g. anything with a let's encrypt certificate)

I was only able to ditch IE for a major customer last year thanks to the new Edge rollout on Windows 10 and Microsoft setting a precedent with their own online services (Teams especially). Moving away from old workarounds to newer technologies will be a gradual process over the coming years.

The problem isn't just IE marketshare. Not every web developer works in e-commerce, on brochure sites or even SaaS apps with a target audience consisting almost entirely of other startups. If you build products for mostly enterprise customers, those customers often dictate what you support, even if they barely even use it anymore. Changing requirements can be difficult.

I remember being asked by a large international company to build a web app in "HTML5 but it must work with IE6" back in the day. Most of their actual users were on Firefox or using iPads.

Government, healthcare, many other industries that don't move as quickly for various reasons.

I think pretty much all the things in the article are nice-to-haves that could simply just be omitted in IE.

If you want a modern UX, use a modern browser.

Is Internet Explorer still that popular to require extra support?

Depending on your market, it's not about the raw popularity. If you are selling to business, many of them are running ERP systems that depend on IE11 and will never be updated. However the knowledge that IE sucks is well established outside of developers at this point. We sell into business and only officially support Chrome and Safari. When people run into common issues we tell them to switch from IE to Chrome, and 90% of the time they respond as if they screwed up not us, and that they should have thought to try in the non-sucky browser.

I see Edge at 3.37% and IE at 0.62% in that chart.

Some industries (government, hospitality, health care, some travel) have proportionally more IE users unfortunately than the general population

I have stopped supporting IE a long time ago. Haven't heard any complaints. Granted I write business software and we simply tell them we don't support IE or Safari and people are fine with that. Most people use either Chrome, Firefox, or Edge.

That being said, in some places IE is still enforced and you have no choice. I used to work at a place that enforced IE6 for the longest time, that was really awful.

I've inherited a pretty bad codebase written in PHP and JS, mostly Dojo. Its UX is based around a lot of dialog windows. Some dialog windows' contents are too big, so that a scroll bar would appear. One issue they had before I came in was that in those cases, the save and close buttons in a bar at the bottom of the dialog would also end up at the bottom, so they had to scroll all the way down.

This issue had been open for years. IDK if the previous developer had a look at it, but the interim guy - some PHP consultant - spent a few days trying to fix it.

I added `position:sticky` to it and fixed it in minutes, everywhere. Not to boast or anything, but that's all it took. Okay fine I am boasting that my google-fu was slightly better than the other guys.

Didn't know about the `loading=lazy` attribute on images yet, mentally I was still thinking of plugins and JS libraries that take care of it for you.

Pretty cool. Nothing beats reading the docs, being curious.

Weird notion:

Is there a FindBugs for HTML, CSS, JavaScript?

Such a tool might have to analyze the live DOM, with the actual behavior, to infer what's actually happening, to better suggest refactorings.


A gentle reminder to anyone dismissing this theme of making websites work with less javascript:

Amazon.com works great with NO javascript. Seamlessly.

You can use Facebook without JS as well: mbasic.facebook.com

I'm not sure if it's completely JS-free but Gmail also has a Basic HTML view, although you must enable JS in order to login to your Google Account.

However, this seems like a weird comment. Should it be surprising that some of the world's largest tech companies with effectively infinite resources are able to provide a JS-free version of certain services?

are able? not surprising. that they do, is nice though. twitter got rid of their no-js site, so it's not a given, even for huge websites. amazon does stand out in that their main site still gracefully degrades well, not some alternate version that's stowed away somewhere.

I am grateful for the gmail html version though. ever since they redesigned gmail I've been using that, since it still has the old interface. and it does have optional javascript based enhancements here and there, as you say (e.g. suggesting people from your contacts when typing in a recipient)

although i recently found out you can't cancel prime without javascript. took me ages to figure that one out since the site usually works for the most part

The -webkit-clamp-line feature would be super cool if it didn't require you to use `display: -webkit-box` and `-webkit-box-orient: vertical` to achieve it: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-lin....

Not to downplay the potential usefulness of some of these, but some of the reasoning for them that is presented is making some assumptions about how the Javascript is done, and those assumptions might not be true.

JavaScript can load just as fast as CSS etc if done carefully. If you really want to, you can put some JS right in the HTML file, immediately following the elements it is going to operate upon, changing the display of the elements before they are even rendered to the screen. Users will experience no delay (or flashing) at all. Whether or not that is considered good practice is another matter, but it most certainly is possible to eliminate the delay that is discussed in the article without abandoning JavaScript approaches.

The problem is when people require a big framework be loaded just to do simple things. Or, I guess they write JavaScript that is so complicated that it causes a noticeable delay simply due to loading the massive code. But that is an awful lot of code. The examples given would never need more than tiny amount of JS code.

There are other reasons, of course (people who turn off JS still exist, I'm told), but as someone who simply knows JS well but doesn't know nearly as much about CSS (which has far too many surprises and special cases for my liking), I tend to be of the "if all you've got is a hammer, everything looks like a nail" mindset. So I'm unlikely to figure out how to do something in HTML/CSS if I can do it instantly in JavaScript. (obviously I do regular styling in CSS.... I'm talking about the more advanced stuff as per the article) That's just my reality, right or wrong.

> If you really want to, you can put some JS right in the HTML file, immediately following the elements it is going to operate upon, changing the display of the elements before they are even rendered to the screen.

This is indeed a cool trick I have seen in use in the wild. Can it work with CSP, however?

That would have been my first question as well.

It can work, if you specifically add the hash of that bit of JS to script-src or use the nonce based approach (I never figured that one out).

Otherwise it's unsafe-inline, at which point you may aswell not bother ;)

On latest Chrome, using hashes for scripts now requires 'unsafe-hashes' to be specified in your CSP.

Correction: this only applies event handlers, e.g. onclick='someFunction()'

What’s “CSP”?

Content-Security Policy, a header to define allowed script sources etc.

Just in case, in Sciter (https://sciter.com) you can declare

   div {
   div:checked {
and all divs will behave as checkboxes - will toggle :checked flag on clicks.

Same way:

   div {
   div:checked {
Or even :

   table > tbody { /* scrollable table body, behaves as <select>*/ 
     overflow-y: auto; 

   table > tbody > tr:current { /*current "option" */
Also you can put this in your markup:

   <frameset cols="120px,*">
to have split view.

No script is required for all these.

An unrelated javascript technique I learned on HN sometime ago.

`document.getElementById("id")` can be replaced by `window["id"]`.

That seems like a dangerous idea to me. If you decided to have an element with an ID of, say, "print" you'd end up getting the window.print method instead of the DOM element you're expecting.

Ironically it took 20 seconds to load this site.

That's obviously not the JS though, because it takes a while to connect and download the first request rather than taking a long time to render. It's likely that the server is just struggling under an unusual amount of traffic right now.

So no, its not ironic.

a basic question - why there is no multi threaded browser ?

Flow is attempting to do just that.


Nice ! thanks that's an interesting read. All this javascript is single threaded in browser is all so limiting.

Saying that JavaScript is single threaded isn't accurate anymore. Even the article we just read mentions that you can run multiple threads with WebWorkers. The problem with JavaScript is that the main thread may* block the UI.

* Why may? The older APIs such as document.write and synchronous XHR do but modern browsers already warn against that. And the modern APIs don't block the UI because they are asynchronous and work with callbacks or promises. Bad JavaScript code can make the UI sluggish though, people should be performing complex tasks on a WebWorker but that's not as easy or as obvious as the default of performing them on the UI thread. The same problems can happen in native Windows programming for the same reason, the UI thread being the main thread. This is a bad design decision from decades ago that will likely haunt us for many more decades in the desktop OS and on the web.

> Saying that JavaScript is single threaded isn't accurate anymore. Even the article we just read mentions that you can run multiple threads with WebWorkers

This doesn't make Javascript multithreaded. It means you run single-threaded programs in separate containers and pass messages between them.

Who cares about the details - you can create multiple workers, running on different threads. That’s multithreading.

> Who cares about the details

People who actually care about multithreading

> you can create multiple workers, running on different threads. That’s multithreading.

It's not.

If you mean multithreaded as running separate OS threads I've got to agree with you but the definition of thread isn't limited to just that. I don't know about the internals of web browsers or whether they use OS threads or green threads or a combination of both for web workers but they are threads and that's how the MDN calls them too: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers...

> and that's how the MDN calls them too

These are the browser's background threads, maybe. They don't make Javascript multithreaded or even Javascript runtimes multithreaded.

More here: https://news.ycombinator.com/item?id=27397555

I'm not sure I get your point. It's more or less what I said, it isn't using real OS threads but it is doing something similar to green threads. It isn't true multithreading in the sense that it doesn't spawn an OS thread but it spawns lightweight (or green or simulated) threads with their own VM.

> It's more or less what I said, it isn't using real OS threads but it is doing something similar to green threads.

It's not even green threads.

Also, literally on the page you linked:

=== start quote ===

The Worker interface spawns real OS-level threads,

=== end quote ===


> it doesn't spawn an OS thread but it spawns lightweight (or green or simulated) threads with their own VM.

It spawns an isolated process. Javascript as a language and its runtime cannot support threads. To do "threads" they basically initialise a new instance of JS runtime.

This is not "threading" by any definition. MDN page may call that for the sake of people who end up using it, but these are not:

- threads

- green threads

- lightweight

If in doubt, you could try and find any implementation of a thread or a worker in the JS VM: https://github.com/mozilla/gecko-dev/tree/master/js/src/vm

It's not there, because workers are implemented at the DOM level, in the browser: https://github.com/mozilla/gecko-dev/tree/master/dom/workers

It's an outside implementation, running processes inside the host, and letting processes communicate using memory-mapped values. 20 years ago no one in their right mind would call this "multithreading in language X". It was "app 1 written in any language is communicating with app 2 written in any language via memory-mapped files". Now people who've never seen anything outside web development call it multithreading.

[1] Fun trivia: original implementation literally used a runtime per worker: https://blog.mozilla.org/luke/2012/01/24/jsruntime-is-now-of... It still uses a CycleCollectedJSRuntime per worker, but I'm too lazy to dig through source code for further details.

> It spawns an isolated process. Javascript as a language and its runtime cannot support threads. To do "threads" they basically initialise a new instance of JS runtime.

Sometimes I need an answer as blunt and direct as that one to understand something, thanks.

Unfortunately, there's also a dearth of tech articles discussing how the many parts of web APIs work, and how they are implemented. High-level articles help with using them, but will always simplify things :)

Does the presence of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... fit your definition of multithreading?

Literally on that page, emphasis mine:

=== start quote ===

To share memory using SharedArrayBuffer objects from one agent in the cluster to another (an agent is either the web page’s main program or one of its web workers), postMessage and structured cloning is used.

=== end quote ===

And, of course, they are almost exclusively used with Web Workers because it makes zero sense to use them in the context of a single page. They are basically memory-mapped files, but for the browser, and their presence doesn't make Javascript and its runtime multithreaded.

There's also a good overview on the history of concurrency and parallelism in JS here: https://exploringjs.com/es2016-es2017/ch_shared-array-buffer...

IIRC Javascript can't even be made multithreaded because there are places in the spec that can't work in a multithreaded environment, but don't quote me on that.

I think you are missing the key point there.

> However, the shared data block referenced by the two SharedArrayBuffer objects is the same data block, and a side effect to the block in one agent will eventually become visible in the other agent.

This gives you shared memory between two threads. Sure the entire address space isn't shared but I find it hard to deny that this is threading.

> This gives you shared memory between two threads.

This is the key point you're missing. It's not "two threads". It's to different isolated tasks/processes.

Shared array buffers are quite literally what memory-mapped files have been used for over 40 years [1]

=== start quote ===

Another common use for memory-mapped files is to share memory between multiple processes. In modern protected mode operating systems, processes are generally not permitted to access memory space that is allocated for use by another process... There are a number of techniques available to safely share memory, and memory-mapped file I/O is one of the most popular. Two or more applications can simultaneously map a single physical file into memory and access this memory.

=== end quote ===

That's all there is: two separate, isolated processes accessing the same memory. This doesn't make Javascript multithreaded in any way, shape, or form. Browsers give you a rather awkward way to run a separate tasks in Javascript and give you message-passing and shared memory as a way to communicate between them.

Had browsers been able to run other languages than Javascript, you would be able to run one worker in Javascript, and another in SadlyNonExistentScript, and literally nothing would change: you would still have the same postMessage and SharedArrayBuffer as APIs provided by the host.

[1] https://en.wikipedia.org/wiki/Memory-mapped_file

Edit: Here's a nice rundown on how this is implemented in V8 https://livecodestream.dev/post/how-to-work-with-worker-thre...

=== start quote ===

To run workers isolated from each other when Javascript doesn’t support multithreading, worker threads use a special mechanism.

We all know Node runs on top of Chrome’s V8 engine. V8 supports the creation of isolated V8 runtimes. These isolated instances, known as V8 Isolate , have their own Javascript heaps and micro-task queues.

Worker threads are run on these isolated V8 engines, each worker having its own V8 engine and event queue. In other words, when workers are active, a Node application has multiple Node instances running in the same process.

=== end quote ===

Wdym, all browsers use some kind of multithreading.

I like the snap scrolling feature, i didn’t know that one

Same thing using a language unifying HTML, CSS and JS


To be improved for non squared pictures

Pretty embarrassing how slow this website is too load, considering the dude's core competency.

It wasn't slow for me and also the page is on the front of HN right now which often hammers web servers.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact