It is vain to do with more what can be done with less.
Our HTML/CSS focus up to this point has been relatively broad, to start with the basics. Here we want to sand down some of the rough edges, and introduce you to specific, advanced techniques you can use to refine and enliven your workâstill with just CSS, no JavaScript (yet)!
-
Overflowing content | MDN
There are going to be a lot of MDNs, here. -
Font metrics,
line-height and vertical-align
AÂ deep-dive on type positioning. -
::before and ::after - CSS Tricks
Another great CSSÂ Tricks article. -
Filter | MDN
Back to MDN.
A good pattern to follow in web development is to use each technology only for what it does bestâusing HTML for semantic meaning, CSS to handle how we form a page, and, later, JavaScript to introduce more interaction. But even before we get to JS, we can start to layer in some more liveliness in our CSS.
Letâs look at some examples.
Overflows and scrolling
An overflow in CSS happens when there is too much content to fit in a containerâusually because you have manually constrained its height
or width
. (By default, the browser will try to show you everything!)
We can use this behavior intentionally to crop our content or create scrolling areas:
Importantly, this creates a new stacking contextâwhich means things with position
(and some other properties) will now use the overflow container as their reference/origin:
Precise text positioning
HTML renders a lot of extra space around text elements, called the line box (or, in design software parlance, the bounding box).
It is based on the font-family
, the font-size
, and the line-height
, which basically means it is different all the timeâand crucially, often different from Adobe/Figma to HTML. This makes it difficult to position type preciselyâespecially at large, expressive sizes like your headings! Itâs always annoying, and youâll often be adding/subtracting your spacing (margin
or padding
) to account for it, if you want to line everything up just right, optically.
Letâs avoid it. We can use pseudo-elements, ::after
/ ::before
âwhich are entirely created by CSS, not in your DOMâto negate this vertical space with a negative margin. By doing this on the pseudo-elements, we can still position the parent element normally, otherwise!
Michael calls this tactic ânegating the bounding box.â
Text ragging (sorta)
Weâve gone on-and-on about how you canât treat the web like printâalways perfectly ragging your text for nice, smooth blocks. In modern (responsive) web design we donât always know what our text will be, nor where it will wrap!
But we can do a handful of things to make for better ragging/wraps, given the unknownsâjudiciously using hyphens
/­
, <wbr>
, <nobr>
, and
to somehwat control your line breaks.
hyphens
/ ­
and <wbr>
The hyphens property allows long, multi-syllable words to be hyphenated when they wrap across multiple lines. This can be done automatically by the browser, or by manually inserting ­
(for soft hyphen) as an HTML entity:
Somewhat similar to ­
, the <wbr>
is a (void/<br>
! You can use these to control where single long word will wrap, without a hyphen:
<nobr>
and
More often, youâll want to keep certain words togetherâto avoid a widow or orphan, or to keep important/related text togetherâlike in dates, November 8, or with names like van Zanten.
You can wrap multiple words (or whole phrases) in a <nobr>
tagâkeeping in mind that like <em>
or <strong>
, the default behavior is cleared by most resets (ours included)âso you have to restore the property in CSS. You can also use a manual
entity between words:
Beyond these manual interventions, you used to need JavaScript to fully balance your linesâbut text-wrap: balance;
is finally becoming available!
Hanging punctuation (kinda)
Ideally we could set punctuation outside of our text blocks, for visual alignment based solely on the lettersâa traditional design technique called hanging punctuation. There is actually a CSS property for this, but only Safari supports it. But we can still approximate the behavior, at least for quotes:
When in doubt, The Elements of Typographic Style explains these conventions. But also, as Bringhurst says, âread the text before designing it.â Always put yourself in the mind of your reader!
Filters!
CSS can apply visual effects on elementsâadjusting their graphical display after they are laid out and rendered in the pageâwith the filter
property:
These also correspond to backdrop-filter
valuesâwhich apply the effect to the page behind an element! (Safari still needs prefixed -webkit-backdrop-filter
to understand.) Youâll often use these in conjunction with a mix-blend-mode
for interesting layer-blending effects.
Transforms!
Beyond our standard sizing and layout afforded by CSS, you can also visually manipulate elements using CSS transformsâscaling, skewing, translating, or rotating elements after they are laid out in the DOM. Itâs like grabbing the âcorner handlesâ in Adobe/Figma!
scale()
/scaleX()
/scaleY()
/scaleZ()
/scale3d()
- Change the displayed size of the elementâas if it is an image.
skew()
/skewX()
/skewY()
- Tilt an element to the left or right, like turning a rectangle into a parallelogram.
translate()
/translateX()
/translateY()
/translate3d()
- Move an element left/right and up/down, and also in three-dimensional space.
rotate()
/rotate3d()
- Rotate the element.
perspective()
- Doesnât affect the element itself, sets the distance between the user and theÂ
three-dimensional plane.
The units for these are all a bit different; MDN is your friend here, as usual. You can apply single or multiple transforms, which are written space-separated and applied one after the other:
.rotated {
transform: rotate(-5deg);
}
.rotated-and-scaled {
transform: rotate(-5deg) scale(120%);
}
Keep in mind that these transformations are applied after the rest of the CSS is parsed, and thus treat your element a bit like an image. And like overflow
, above, transform
also creates a new stacking context for its children.
You shouldnât use transform
for layout, per seâas in, donât use translate
when margin
, padding
, flex
, or grid
can achieve your layout. (This is bad practice, and usually very brittle.) Use transform
only for what other properties canât accomplish!
Transitions!
CSS transitions allow us to more seamlessly move between CSS property values.
Instead of having a property take effect immediately when a pseudo-class is applied (or later, and more commonly, with duration
), and with a specific acceleration (timing-function
), or a delay. Motion can quickly get very complex!
Youâll often see a transition
in shorthand:
.some-cool-transition {
transition: all 2s 1s linear;
}
.some-cool-transition {
transition-delay: 1s;
transition-duration: 2s;
transition-property: all;
transition-timing-function: linear;
}
You can also control how different properties of an element transition independently, with a comma-separated list:
.some-cool-transition {
transition: background-color 2s linear, transform 1s ease-in-out;
}
.some-cool-transition {
transition-duration: 2s, 1s;
transition-property: background-color, transform;
transition-timing-function: linear, ease-in-out;
}
Sometimes the shorthand here is easier than discrete properties, where you have to maintain the same order across all of them. Itâs all the same to the computer!
Often, CSS transitions will be used with JavaScript adding/removing classes, to make a state change less abrupt. For now, weâll use pseudo-classes to demonstrate:
Nearly all CSS properties can be transitionedâbut keep in mind that changes that cause a reflow (re-triggering layout, sometimes called paint) are slow and can make your page feel glitchyâespecially when you start having many of them. Each in-between state causes the browser to re-render your entire document! So stick to changes of color
, opacity
, and transform
for the smoothest performance.
And animations!
Sometimes, transitioning a property from one value to another isnât enoughâyou may need more complicated (or repeating) motion behavior. CSS animations allow precise state sequencing with @keyframes
(akin to⊠keyframes or a timeline in other software contexts).
To create a keyframe animation, we define an elementâs initial state in CSSâthen an animation
property, which includes timing and behavior, as well as an animation name (something that you make up). Again, youâll often see these in shorthand:
section {
animation: blinking 3s infinite ease-in-out;
}
section {
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: blinking;
animation-timing-function: ease-in-out;
}
Importantly, we then define the actual keyframes of an animation in a separate at-rule. Each keyframe is specified with a percentage of the animationâs duration, and can specify multiple propertiesâa bit like selectors for the time:
With great power there must also come great responsibility.