HTML Tips (2020)
markodenic.com
markodenic.com
I wonder what else in the HTML5 spec I've missed...
Thanks for sharing this!
Although, one could argue that a <progress> is just a <meter> where the optimal value is 100%.
There's nothing more frustrating than when I'm trying to read through a page and my spot keeps getting pushed up and up because of dynamically loading elements.
That being said, lazy loading does at least some of the time work "invisibly" with images getting loaded before they would become visible. It's up to the browser to decide how aggressive it wants to be about this.
It used to not work for responsive images. We had to do tricks like pseudo elements with padding set to a percent value: https://css-tricks.com/preventing-content-reflow-from-lazy-l...
https://jaeh.at works fine when reloading, no layout changes, and the layout changed slightly before i fixed it using width & height.
https://noncon.org does not (and i had no time to fix, might be because width of images is not set, might be something with the css position/float layout, we had about a week to setup the whole conference infrastructure, including the streaming server, layout flashing was my last concern at the time and i kept myself too busy since then to fix something so trivial...)
sorry for the personal links, just examples i knew from the top of my head because i built them ;)
I've dynamically updated <datalist> on a site, only to find out that browsers will only show options that strictly begin with whatever you've typed into the <input>. When you want to do Google Search-esque suggestions, that's a problem. I don't know how to override that to force it to show all options.
An awful lot of "AJAX" Javascript use could just be frames and iframes, if they were somewhat better.
Form validation should be built-in (with optional light JS for defining non-built-in validators). The browser should supply a lot more input types, including some kind of payment integration. It's absurd those things have to be built over and over and delivered by the website.
I could go on. It's a damn shame.
Have you used pattern attributes?
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes...
It's heavy-weight, fragile, lots of implementations are framework-specific, and most of them are horribly buggy, but it's nonetheless a must-have feature in many cases. It'd be a great candidate for better support in the browser, generally, if we're going to insist on using it as an application platform.
I don't remember having that last time I had to implement serious drag and drop, about 4 years ago.
This just made me laugh because it is so true. I thought it was just my stupid luck that I keep working with companies obsessed with drag and drop. But you are right. I have seen companies blow hundreds of thousands of dollars implementing drag and drop on a trivial feature. The same company will then complain about spending a few thousand dollars implementing a security feature or implementing training programs to teach employees about the importance of securely handling PII.
Edit: PII = Personal Identifiable Information (social security numbers, credit cards, birthdates, etc).
You are both right. Drag and drops are incredibly intuitive for users. It feels natural to most people and is easy for many of them to use.
But the parent comment is also right because drag and drops are not very USABLE. Meaning that if someone is using a screen reader or an unusual device (phone, kiosk, kindle, etc) the drag and drop functionality may not work well for them or might not work at all. It might be INTUITIVE on what the user is supposed to do, but it isn't USABLE. We have all encountered non-usable interfaces that we simply can not interact with for various reasons. This also becomes a concern for accessibility. A screen reader may not be able to read it to someone who is blind. An older device might not be able to display or operate the drag-able functionality. A user that relies on something like "Voice Control" may not be able to use your drag-and-drop system.
Ideally you would do both. You could show an interface that has up and down arrows for each item to move items manually. But also make those elements drag-able if users choose that option. But this takes more and more development time. That is the constant battle between software engineers and decision makers. Anything is possible with enough development time, but decision makers are quick to move developers along when the item is "good enough", which generally means the feature works on the decision-maker's devices.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/in...
The problem is that some HTML form controls cannot be styled with CSS to render consistently across browsers. So, many sites fall back on JavaScript to render the control. Here is an example from 2016 on styling HTML checkboxes and radio buttons to make them larger (which, as far I can tell, is still a problem): https://designnotes.blog.gov.uk/2016/11/30/weve-updated-the-...
And iOS 14.5 (well, 14.5.1) is also current: https://support.apple.com/en-ca/HT211808#1451
But we'll have to wait a few weeks to months before all Safari users upgrade and see the latest improvements.
Does that mean only fully up-to-date macOS gets it, or do Safari versions move independent of the OS?
In rare cases, Safari features require a capability only available on the latest macOS.
On Firefox, the date picker is good and I can easily navigate to a year from muscle memory. The same wouldn't work on mobile, so they have different UI and controls. I don't want to use iOS style date pickers on my Android, or the other way around just for consistency.
Many custom date pickers are sluggish and has bad UX, and adds a lot of extra validation complexity with pseudo elements.
IMO we would be better off moving most of these things out of the browsers and into some kind of web component standard.
This way, modules can declare that they need certain functionality and then the end user provides it: instead of npm-style infinitely-deep dependency trees.
https://gbracha.blogspot.com/2009/06/ban-on-imports.html?m=1
The lazy-loading option for img elements is news to me, but I think I'd still prefer to use JavaScript for that task. Same probably goes for the dialog element actually now that I think about it.
Having a simple HTML5 option might seem cool, but I like to keep the actual logic in JavaScript and to use HTML just for page structure. Basically, I prefer to depend on HTML as little as possible for user interaction/behaviour.
HTML: what an element *is*
CSS: how an element looks
JS: what an element *does*
There's always overlap and blurred lines but that's one of the joys [2] of developing for the web.If you're using a framework like React you don't even care about the markup, it's all abstracted away -- but in that case, you care even less about neat little HTML5 additions, you've got components and they're woven into your event dispatch and state already.
[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/di...
[2]: horrors
There is a polyfill that makes it works even on IE.
I embraced and use it on a product that it's remaking&modernizing all the frontend. Sadly, when I take the decision a few years ago, I thought that <dialog> would be supported for all browsers, but looks that adoption has been paralyzed.
I prefer to depend on the user agent for user interaction and behavior. Javascript and all its potential for tracking, malware, side channel exploits, etc. should be abolished from the safe web.
For CSS I recommend Wes Bos tutorials about flexbox and grid - https://wesbos.com/courses and this blog: https://ishadeed.com/articles/
Does anyone have a good way to approach this? Or for HTML in particular, is there some way to keep up with it (on a decade time scale, not this year's framework hype)?
Its author has been in the web dev field for decades and has written multiple books on the topic. She has got some chapters written by experts in respective fields (CSS by Eric Meyer and so on)
As much as W3Schools is hated, I find their HTML/CSS/JS guides to be a lot simpler to understand than MDN: https://www.w3schools.com/html/default.asp
I am sure there are a lot of good stuff there, but quite a lot has happened with html/css and browser support since late 2011.
Also read MDN often.
"Performance tip. You can use the loading=lazy attribute to defer the loading of the image until the user scrolls to them."
Can someone explain to me when this is useful?
As a content consumer I'm frequently annoyed, when I have to wait for images to load while scrolling.
As a content creator I understand the idea that I might potentially save the consumer some bandwidth, given they might - against all odds and for whatever reason - decide not to scroll down. Kidding aside I think that as a creator I should optimize for the readers that are thoroughly interested in my whole content and therefore I should preload and not lazy load.
It makes a non-negligible impact on bandwidth usage and page load time.
Chrome seemed to behave this way as well when I tested it a while ago. It's covered in the spec: https://html.spec.whatwg.org/multipage/urls-and-fetching.htm...
It's a longish travel report, lots of photos, interspersed with comments. I think it might be nice not to have all of them loaded in the beginning. Especially since random visitors probably won't read it till the end.
That's the experience most javascript solutions gave you. This browser native solution will load images _before_ they're visible in the viewport so you do not get the fading-in flashes you often see. Combine it with setting the width and height on an element and your page also won't shift around as you scroll.
This will actually optimize for the reader as it will improve the time it takes before they can interact with your page. I also think you'd be very disappointed if you see the percentages of people that end up scrolling on any given page.
Now I can have proper zero indexed lists and annoy friends. Chrome even supports negative integers.
<ol start="0.5">
Is not supported...
Luckily not that many sites have it, but come to think of it, does anyone know of an add-on or something to disable the lazy attribute?
In Chromium based browsers set "Enable lazy image loading" to disabled in about:config
In Safari it's still an experimental feature you have to enable manually.
.
Of course since Safari doesn't support it yet plenty of sites lazy load via classic JS style solutions and trying to fix those is like playing whack-a-mole.
first of all that is not limited to those kinds of links, generally, in Windows this used to be handled by registering a uri scheme in the registry and associating it with an application for handling that uri scheme, mac has a similar method https://kaihao.dev/posts/Make-your-own-custom-URI-scheme-res...
it used to be that Linux didn't have a way to handle uri schemes (like back in 2006), but it seems to no longer be the case https://unix.stackexchange.com/questions/497146/create-a-cus...
so you can use any uri scheme, magnet links etc. in a link, you can also do stuff with JavaScript with those uri schemes, for example window.location = "tel:some telephone number you want to call".
Nowadays if you have not used a uri scheme in a browser on a particular OS and you click on a tel:phone number link you will end up getting asked if you want to associate links of type tel with a particular application for handling it (assuming you have a handler for tel uri scheme on your OS - on mine it asked me if I wanted to open with FaceTime, as I am on Mac). It used to be that it would just open whatever application was associated with the scheme. I guess it is a security measure.
So you could theoretically end up in a situation where someone does not have a handler for a scheme you are using to make a link. If you want to avoid this for tel and sms links detect if the user is on a phone of some sort because of course those will have handlers for tel and sms built in. Otherwise you need to take your chances.
on edit: a not very great article I wrote on this subject in 2003 http://www.devx.com/webdev/Article/17120
I recently worked on a page (e.g https://php.watch/rfcs/fibers) that I didn't want to set inline CSS to set a dynamic width for an element. Helps me not use a strict CSP.
I kind of abused the progress element because it has customizable width. Elements that support a width attribute (object, iframe, image, etc) didn't fit that well. Progress elements are pretty nice, supported almost everywhere it mattered to my audience, and with some pseudo properties I never heard before, I could customize the colors and other properties as well.
Also both <progress> and <meter> would be an order of magnitute more usable if non-linear functions (such as sin(), cos(), pow(), exp(), etc.) were allowed as values in CSS transformation matrices so that I could use <meter> instead of <svg> when my designer wants the meter bar to look like a speedometer (which is a quite common, and a valid design choice).
1: https://stackoverflow.com/questions/8094835/how-to-style-htm...
1. Lazy loading: generally speaking, just don’t do this. It’s much better than doing it in JavaScript (especially when combined with a blurry image until it loads, which I and many others find surprisingly disconcerting), but if you’re not very close to the server (which very commonly means “if you’re not in the USA”) then it commonly just means that the images won’t be loaded when you scroll to them. Also there’s the whole load-the-page-then-go-offline problem, which I feel is more common than most realise. Instead, I say: if you care about the image, you very probably shouldn’t use lazy loading on it; and if you don’t care about it, hey, why not just remove it?
2. Telephone and SMS links: the unfortunate trouble with these is that you can’t detect whether they’ll work or not. If they don’t work, they’ll probably just mysteriously do nothing, and you can’t reliably detect that, because your code may not be able to detect if it did do something. This is all just something to be aware of.
4. The <meter> element: see also the <progress> element. Two similar elements that differ in semantics as to which you should use.
6. Fieldset Element: a point in the demo that’s not ideal is that the gap between the radio button and the label isn’t clickable. One way of fixing most of this is to start the label immediately after the radio button, with the leading whitespace inside it rather than before it. But depending on user agent and content styles, even that may well be insufficient, leaving a tiny gap. In a situation like this, the ideal is to put the radio button inside its label, and make the label `display: block`, or something else that achieves this effect (if done carefully, you might even find `display: grid` suitable nowadays).
7. window.opener: it suggests including rel="noopener" or rel="noreferrer" in order to remove the opener; I think it’s worth noting for explanation that noreferrer implies noopener (because you could access the referrer through the opener): https://html.spec.whatwg.org/multipage/links.html#link-type-....
10. The `spellcheck` attribute: this is actually a tristate attribute: it has states true, false, and default (which mostly means “inherit”). `spellcheck="true"` can be written more briefly as just `spellcheck` (which, in the HTML syntax, is equivalent to `spellcheck=""`). See https://html.spec.whatwg.org/multipage/interaction.html#attr... for more info.
12. HTML Accordion: I have just two general remarks on web design here. ① If you’re using something like this for FAQs, please strongly consider not using an accordion, but instead having a table of contents with links to each question, followed by the questions (as headings) and answers (as paragraphs); or if you’re not willing to do that, please provide an “expand all” button through JavaScript. ② On the web, accordions have historically regularly been implemented so that at most one item of any set will be open: that opening another closes any that was open. Please don’t do this. It’s a pain. I just want to read stuff, I don’t want to have to interact further. (See also my “expand all” request in part one.)
14. `download` attribute: this can also take a value, which will be used as the filename. This is useful if you generate a file client-side as a data: URI. It’s not so useful outside that, actually, as you’re probably better to get the server to set the filename via the content-disposition header, or if you’re generating a file client-side with a blob: URI, use File instead of Blob so that you can set the filename.
15. .webp: significantly overrated, in my opinion. It doesn’t give anywhere near as big a boost in compression relative to properly-done JPEG as people think (like under 10% a lot of the time). Now AVIF, that’s another matter.
16? Video thumbnail: an interesting thing that has just occurred to me on this is that the poster attribute doesn’t let you provide multiple formats like <picture> does. Hmm, so you probably keep serving a JPEG here instead of WebP, AVIF or whatever else. Wonder if anything can ever be done about that. I can imagine them making poster="#foo" followed by <picture id="foo"> inside the <video> work. Eek, this similarity to svg:use made me realise that you can actually achieve this goal with SVG already: the code below ought to do it; ugh!
poster='data:image/svg+xml,<svg …><foreignObject …><picture xmlns="http://www.w3.org/1999/xhtml">…</picture></foreignObject></svg>'
———If you enjoyed this article, see also https://markodenic.com/css-tips/ from the same author on CSS tips, discussed here nine days ago at https://news.ycombinator.com/item?id=26945263.
I was saying the same thing but then I realized something. The thing about webp isn't about how it compares to jpg[0]. Png on the other hand, with all those logos and some with transparency. Webp can replace these with only a fraction of png-size.
Anything photographic, where quality is priority and transparency isn't required I find jpg to be finer quality.
[0] Altough that's often the narrative.
Heh, this is even another place where you can invoke SVG (though slightly less awful than the HTML-in-SVG-in-HTML I just mentioned, yet nonetheless pretty unnecessary nowadays): you split the alpha channel out into a separate, greyscale, image, and use it as a mask for the other image. Thus you can add a PNG or JPEG alpha channel to your JPEG. https://peterhrynkow.com/how-to-compress-a-png-like-a-jpeg/ is a good description of the technique; and JPNG.svg, at https://codepen.io/shshaw/full/LVKEdv, is one tool to generate such things.
Webp/png can be very useful in the sense that there is a broad understanding about how to work with plain images. A low barrier to entry, and easier collaboration in some situations.
I did not know about the alpha channel workaround. That's nice to have in the toolbox, Thanks.
Choose an example png(1) but had to redo with png(2) because tinypng.com won't chew a file larger than 5MB.
png 2.4MB ← original png
png 2.1MB ← Trimage image compressor
jpg 876.6kB ← Converseen image converter
jpg 808.2kB ← jpegcrush ← Converseen image converter
png 743.0kB ← tinypng.com (impressive!)
webp 416.3kB ← Converseen image converter
The model a lot of devs have of the user's connection is a huge, unmetered pipe, possibly with short periods of intermittency (being on a train, etc). The web can be not such a great place if you don't match that model.
You could turn it off if and when you face any bandwidth limitations - if it was a mature system, then you could turn it off globally in the browser.
Intermittency can be overcome with the right technical approach. It's potentially great for intermittent connections, since it can pre-download materials whenever your connection is good.
I guess it won't be supported between different sites, because it introduces risky conflict between tracking and privacy, that hasn't been legally resolved. (Any external link creates a privacy/tracking/security/authentication hole, whether the user clicks it or not). Maybe that's what has ultimately prevented wider adoption.
I want to provide a smooth experience similar to how you'd watch your gallery on Android or iOS.
So this means no, I don't want to have the user click links with years and months on them, I want a single page.
But do I want to load literally THOUSANDS OF IMAGES at once? No.
I want to know where on the page I am, and load the visible images, and also few rows above the fold and few rows below the fold.
And I can do this with JS.
What's the lesson here? "They won't be loaded when you scroll anyway". They can be. "HTML is much better than JavaScript" sometimes (often) it isn't. "if you care about the image, you very probably shouldn’t use lazy loading on it; and if you don’t care about it, hey, why not just remove it?" Well, BS.
(And yeah, if you need lazy loading, which a large gallery probably does, then loading=lazy is unsuitable as it doesn’t guarantee anything at all, so definitely do it in JS.)
This is actually not great for accessibility. It may be okay for some screen readers if you also populate the for/id attributes, but even then you should test to be sure.
Edit to add:
> Video thumbnail: an interesting thing that has just occurred to me on this is that the poster attribute doesn’t let you provide multiple formats like <picture> does. Hmm, so you probably keep serving a JPEG here instead of WebP, AVIF or whatever else. Wonder if anything can ever be done about that. I can imagine them making poster="#foo" followed by <picture id="foo"> inside the <video> work. Eek, this similarity to svg:use made me realise that you can actually achieve this goal with SVG already: the code below ought to do it; ugh!
My solution is to skip the poster attribute and use a picture with object-fit: cover.
Now there is one I can't believe I missed.
<a href download>Download this page</a>
(Explanation: href is equivalent to href="", and an empty string is a valid URL string, a relative URL with no scheme, no host, zero path segments, no query string and no fragment. # is a valid URL string representing the same URL, but with an empty fragment (rather than no fragment).URLs are resolved relative to what the HTML spec calls the document base URL, and relative URL resolution of an empty string against that will yield that base URL sans fragment, just as resolving # will yield that base URL with an empty fragment.
Note also that you can’t just omit the href attribute, or else it won’t be a link.
Also note that a <base href=…> element will affect the document base URL and is thus likely to make both of these links do the wrong thing.)
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Lists_a...
Which is consistent with the experience I had with the native search widget in this article. I guess nobody uses it, so it's full of bugs and UX issues.
1. The source element also accepts a media attribute with the same syntax as CSS media queries; the first match (media + type) wins, so typical usage is largest > smallest. If you enlarge the window it’ll automatically load larger images. (Annoyingly, this is not supported on video>source.)
- When styling picture elements in CSS, you actually need to select the img tag. This still trips me up time to time.
Possibly an app that did that sort of thing would be some kind of gallery or other very image-centric app.
And if that were the case, then I would think the image URLs would be dynamic, not burned into the deployment.
A cachebust="yes" attribute wouldn’t be useful in practice because the server would either be serving it to everyone, effectively disabling caching (and which would be better done by actually disabling caching with the cache-control header), or need to decide who to serve the attribute to, in which case there are better solutions. In short, cache busting only works if you have some sort of cache key, which is what the query string technique is all about doing.
<img src="/path/to/file.[last modified timestamp].png">
PHP code for this kind of thing might look like this: function auto_version($urlpath) {
// get a filesystem path
$fspath = $_SERVER['DOCUMENT_ROOT'] . $urlpath;
// if file doesn't exist, don't mess with the url
if (!file_exists($fspath)) {
return $urlpath;
}
// insert last modified timestamp
$mtime = filemtime($fspath);
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $urlpath);
}
Then in .htaccess or equivalent to strip the timestamp back off before serving the file: RewriteRule ^(.*)\.[\d]{10}\.(css|js|png)$ $1.$2 [L]
Whenever the file is updated you automatically start serving a new link which points to the same file, and otherwise you can rely on the browser caching. You don't need to mess around with ?params, which also helps semantically because those incorrectly suggest that the resource is dynamic. integrity="<hash>"
This would kill two birds with one stone: If it changes in HTML, this means:- Please bust cache
- Refetch and ensure, that the fetched file is securely valid
And it could be optional for every fetchable resource (img, video, css, js, etc.)
Frontend devs not knowing HTML, but having complicated and over engineered build pipelines and continous integration for their JS cruft.
I wonder why sites don't load faster or render... ah right Javascript in the mega bytes.
just have one suggestion:
noopener is an actual security issue, the opener object is dangerous!
noreferrer is something we should do for the privacy of our users.
nofollow is for us developers to avoid our properties being connected to other properties (links are not endorsements)
maybe think about expanding that section of the docs :)
actually, rel="noopener noreferrer nofollow" should be the standard and opt-outed from. imho, rel="opener referrer follow" would have been the right thing to do.
https://markodenic.com/css-tips/
https://markodenic.com/javascript-tips/
Happy coding!