Hacker News new | ask | show | jobs
by seanwilson 17 hours ago
> If you “View Source” on any “real” website, you’ll notice that everything has layers and layers of wrapper elements, so you might be tricked into thinking that wrappers are how you solve layout problems. I can’t really agree or disagree here, as I never wrote “production” CSS, but, in my experience, it’s much easier to understand if you do the opposite — restrict yourself to using only markup-meaningful semantic tags, and then figure out CSS which works with the markup you have.

CSS isn't powerful enough by itself to create any layout you want without modifying the HTML. You almost always need wrapper elements to group elements you want to align together for presentation purposes only (e.g. "a vertically centered row containing one paragraph next to two vertically stacked images"), so there often aren't semantic HTML tags that would make sense.

It's similar to how you use numerous groups/frames in design apps like Inkscape and Figma to help align elements, where nobody would suggest you were a bad designer for using groups that don't have semantic meaning.

You can only really avoid wrapper elements for simple Markdown style pages with simple designs, where the CSS for that is straightforward.

I think in these discussions, it needs to be clearer how complex the page designs being discussed are. The CSS advice that makes sense for simple Markdown style pages is very different to what makes sense for a complex web app UI or a highly designed marketing page.

9 comments

20 years ago everyone was sold css entirely on the premise that, once the standards were adopted by all of the browsers, we would all be writing purely semantic html with completely orthogonal and swappable css. And today literally no one designs web sites that way - html today is mostly specific to presentation. It feels like pretty dramatic technological failure to me.
20 years ago everyone was also sold OOP on the premise that inheritance was the best thing to ever happen to programming. Turns out people are wrong sometimes. And especially when they're being idealistic about things.
I feel like CSS would be in a much better place if they went with the Cassowary proposal for layout.

It would avoid the whole mess of block vs table vs float vs flexbox vs grid (and also absolute vs relative vs fixed) positioning.

Basically, it feels like 90% of CSS is it trying to fix its past layout mistakes & limitations.

The concept makes more sense for styling simple document style pages from 20 years ago, but it hasn't scaled to modern designs, complex web UIs and responsive pages that we want to code now, which isn't that surprising.

> we would all be writing purely semantic html with completely orthogonal and swappable css. And today literally no one designs web sites that way - html today is mostly specific to presentation

I think of HTML + CSS as the presentation layer now, and the data lives in your e.g. database and Markdown files, so the data and its presentation are still separate enough.

The idea of just swapping out the CSS to completely restyle a complex site is nice, but people need to accept this hasn't worked out (and not because devs are bad at CSS) and move on.

If you're good, the same HTML serves mobile and web clients. It's a PITA to write, sure, but if that isn't CSS succeeding then I don't know what is. There's a ton of stuff I wish was different about CSS and HTML (and JS), but going from a small portrait device to a large landscape viewport with the same html? HTML does the HTML stuff and CSS does the style stuff. The fact that you have to tweak the HTML and CSS in a loop until it's right, in order to get to the finished state doesn't indight the fact that it's the same HTML for different clients.
GP said:

> completely orthogonal and swappable css.

You're talking about having a single CSS and HTML page for multiple layouts, there aren't the same thing at all.

a lot of semantic features like the document outline algorithm were never actually implemented by browsers so it was hindered from the start
> using only markup-meaningful semantic tags, and then figure out CSS which works with the markup you have

I agree with the approach you are suggesting, but the reason I find these wrappers pop up: it's VERY hard to make components composable without them.

Let's say you want to have a block that adds spacing between each item within it. Easy: it's flexbox with a gap. Oh no, but a child is displayed inline, and has weird vertical alignment. And another child has an unexpected align-self. Now you get wrappers on the children.

Maybe you want a button. It's got an icon with text. You need a wrapper on the text, because without a wrapper you basically can't get anything right (you can't rather bare text with CSS).

How about a checkbox? Should be easy. You want the component to have the checkbox on the left with the text on the right. You want to allow two rows of text, with the first being in bold (the label) and the second row being a description or help text. You wrap the whole thing in a label element because you care about accessibility. But you need a dummy div to render the checkbox, because you can't reasonably style checkboxes. And each row of text needs a wrapper, because bare text. And maybe another wrapper around the two rows, because while you can use CSS grid to position the two rows above each other, lord only knows what the checkbox is inside of and whether it's flexbox or grid, and the height of the label might be weird and jack up the positioning of your text. God help you if any of the rows have text that doesn't wrap and is wider than the width of the checkbox's container.

The unfortunate truth is that you probably don't need the wrappers, but there's an element of defensive coding that just makes it infinitely easier to get things right all the time with wrappers.

> CSS isn't powerful enough by itself to create any layout you want without modifying the HTML.

This is true, but the better you are at CSS the fewer wrappers you'll likely have. It's also easier to manage styles with fewer wrappers, otherwise you often end up having to put things like height:100% on every wrapper to avoid messing up the layout.

> You almost always need wrapper elements to group elements you want to align together for presentation purposes only (e.g. "a vertically centered row containing one paragraph next to two vertically stacked images"), so there often aren't semantic HTML tags that would make sense.

I'd argue that a lot of times those groupings are meaningful.

I think this has changed a lot since CSS Grid, especially. A lot of my HTML work has been removing "wrappers" either physically deleting them or in cases where they are "load bearing" due to some UI framework or component boundary making heavy use of `display: contents;` or `grid-template-${'columns' | 'rows'}: subgrid;`, depending.
I think this is a pretty pragmatic take, and I do something similar with all the web apps I’ve created since I started self employment close to 15 years ago.

As you mentioned sometimes there are unavoidable things you need to do in markup to make it work visually. Although lately grid & flex solve 95% of the problems that crop up for me fortunately.

> You almost always need wrapper elements to group elements you want to align together for presentation purposes only (e.g. "a vertically centered row containing one paragraph next to two vertically stacked images")

Challenge accepted: https://codepen.io/editor/mkantor/pen/019eb65b-5b17-70cc-872...

You aren't entirely wrong, but I think I'd change "almost always" to "often" or even "sometimes". A lot of the specifics come down to how you want stuff to reflow when the content and/or viewport sizes change.

I was thinking more of a document with multiple paragraphs and images, where some paragraphs are grouped with images and some aren't.

In the code from the link, the <body> element is serving as the wrapper element, that gives you a hook to get the layout you want. But when you're not lucky enough to have a semantic wrapper tag like that, you've usually got to add a generic tag help. Or write CSS that's closely coupled with the HTML, so they aren't really separate anyway.

Grouped HTML: p text img img /p Grouped CSS: p:has(img) {...} p img {...}

No group HTML: p text /p img img No group CSS: p:has(+ img) {...} p + img {...} p + img + img {...}

Valid, semantic, easy to target.

Multiple sequential paragraphs all sitting next to two images? Or multiple rows, each containing a single paragraph + two images?

The latter probably would need an element for each row to be maintainable/scalable, but depending on the content, `<article>` could be a semantically-meaningful container. Or (again, depending on the content) it could make semantic sense to put the `<img>` elements inside the `<p>` elements.

This is still adding wrapper elements to get the layout you want. Even if you can force yourself to come up with some vague semantics behind the wrapper elements (that you wouldn't have otherwise added), I don't see how it's much better than using a generic tag and it shows you need to modify HTML to modify the presentation in practice.

Visual design involves a lot of grouping and aligning elements, and there isn't always semantic reasons for it. Grouping is usually best done in the HTML, so it's hard keep this part of the visual design out of your HTML.

Presumably there's some natural semantic relationship between the elements if you're going for that kind of visual layout (and even blind users might benefit from encoding that relationship in the DOM), but I don't necessarily disagree with your overall point.

Sparingly-used non-semantic grouping elements only inserted when absolutely necessary is a pretty different story from the "layers and layers of wrapper elements" that the article mentions, though.

---

> you need to modify HTML to modify the presentation in practice

If you're e.g. grouping together content that was previously unstructured, arguably that's a semantic change as well as a presentational one.

I wouldn’t accept the premise that wrappers (i.e., <div>s) are to be avoided in the first place.

Perhaps less nesting is better in that it is more readable. But if you compensate by writing more complex CSS, then I don’t see how that’s an improvement.

> so there often aren't semantic HTML tags that would make sense.

Pet peeve of mine: there should really be `<grid>` and `<flex>` elements, as well as `<fi>` (flex item) and `<gi>` (grid item) for the child element instead of relying on a div soup with CSS attributes everywhere.

There's nothing stopping you from defining those yourself for your own websites:

     grid { display: grid }
will work in every modern browser.
For that to work I would need to define a custom component from JavaScript, wouldn't I? (and I thought custom components had to contain an hyphen in there name, is that wrong?)
try it!

  data:text/html,<grid><p>A</p><p>B</p><p>C</p></grid><style>grid{display: grid}</style>
afaik to create a CustomElement you need to use dashes, yes, but in this example `<grid>` is an HTMLUnknownElement, which renders just fine. some discussion here: https://stackoverflow.com/a/22545622/2393963
HTML describes the content, not visual display.
If you remember earlier versions of HTML, with all the tables and font tag soup, it was not always the case. Sadly, it was easier building layouts with tables instead of CSS for a very, very long time.
How the elements were abused does not take away from the fact that HTML elements represent their content, not their layout except for <table> which is probably the only the exception.
These elements weren't "abused." It was the only alternative before CSS was around! Then CSS took years (decades?) to catch up to the simplicity of table-based layouts.
Not really. This would not be different to <table> and associated elements, which are arguably better than a div soup.
Yes, really. Even <table> is used to represent the data, not the layout, though it will be laid out as a table but it's probably the only element that does such a thing.