If you have worked with another layout engine other than HTML, you probably think that HTML is hacky and unpredictable. And you wouldn’t be mistaken to think that: sometimes things expand to fill the available spaces, sometimes they don’t. Sometimes you specify a margin and it is respected. Sometimes it’s not. Most developers would feel your pain, but here’s the thing:
HTML evolved over time, and sometimes a bit chaotically. It wasn’t thought out from the start in its current form.
Yet as web developers, we need to use it so we still need to understand its quirks. And first and foremost we need to understand the fundamental philosophy of HTML: it designed to describe pages that flow vertically, as opposed to say something like PDF documents which don’t flow AT ALL (they have fixed layout). Mobile applications are also not really designed to flow so a lot of the UI elements like labels and buttons have fixed positions, while desktop applications (both Windows and macOS) are somewhere in between because you can resize the application window. Keep this in mind: the browser usually assumes you read the content on the webpage from top to bottom and you use the scroll bar to navigate. The Facebook wall would be a perfect example of this philosophy.
A byproduct of this assumption is that divs expand to fill the whole available space horizontally but not vertically. As a web developer, you are also expected to take into account the possibility the user might change the zoom factor of the page (to increase font-size), so it’s important that the application is responsive. Not to mention he or she might view the webpage from a mobile device.
Before we explain the more quirky aspects of HTML, we need to have a basic overview of the box layout of the elements:
So an element will have
- Some content
- A border which can have some thickness to it
- Some padding between the border and the actual content
- A margin which indicates the space between the border and the neighboring elements
Keep in mind that by default the width and height CSS properties refer to the size of the content and they DON’T include padding and margin size, which is a bit counterintuitive.
Here’s what you need to do:
The default value is content-box.
A weird aspect of HTML (if you don’t know about it) is the way margins behave.
Margin collapsing means that if you have two elements with margins set on them, the space between them will equal the maximum of the two margins, NOT the sum. But this happens only vertically. This again has to do with the vertical flow philosophy of HTML.
But there’s another catch: margin collapsing doesn’t happen for the first or last element of a block formatting context. But before we talk about those, let’s talk about…
Float And Clear
The CSS for these elements actually looks like this:
Floats are a standard way of incorporating an image (or some sort of container block) into a paragraph of text. Not only can you have multiple images, but you can actually use both float and clear at the same time.
Keep in mind that floating elements don’t have any effect on the size of the container:
This might not actually be the desired outcome, but it turns out there is a workaround.
What I did was add an empty div at the end of the parent container, like so:
That’s a bit annoying so what you could do is create a CSS class that always appends an html element that does the clearing (like we previously did). This trick is called a clearfix.
Then, all you need to do is simply add that class to all the elements that you want clearfixed.
Block Formatting Contexts
An element generates a block formatting context if it is:
- the root element or something that contains it
- floats (elements where float is not ‘none’)
- absolutely positioned elements (elements where position is absolute or fixed)
- an inline-block (elements with display: inline-block)
- a table cell (elements with display: table-cell, which is the default for HTML table cells)
- a table caption (elements with display: table-caption, which is the default for HTML table captions)
- a block element where overflow has a value other than visible
- an element with display: flow-root
When dealing with blocks, it’s important to know how they affect their children. One such effect is the margin collapsing. Another effect is that block size affects the size of its children. By default, a div will expand to fill its parent container vertically, but there’s a gotcha:
This by default makes just the content to be 100%.
Something as simple as centering something in the middle of a container was problematic before the addition of flexbox. It still is for older browsers that don’t fully support the display: flex CSS specification. Before we get into the quirky cases, let’s see how we solve vertical centering with flexbox:
If you know the height of the panel you want to center you can do something like:
If your browser doesn’t support calc, there are other ways to do it such as using line-height (which works only for text) or using display: table-cell.
Yes, HTML behaves quite unexpectedly if you are coming from something like WPF. As long as you are aware of some of the gotchas of the spec and the differences between browser implementations, developing in it is quite pleasurable.