Learn CSS
web.dev
web.dev
Adam Argyle [1] and Una Kravets [2] created the podcast series. Una mainly drove the overall project to convert the podcasts into this written series. Adam provided technical reviews on the written content and I also believe he created most or all of the self-assessments (i.e. the 'check your understanding' quizzes). Andy Bell [3] wrote all of the content (and demos, I think). Rachel Andrew [4] edited all the content. Rob Dodson drove the engineering work behind creating this new "courses" infrastructure on web.dev. I was hands-off on this project so I may not have gotten everyone's roles exactly correct, but I do know these were the main people involved.
[1] https://twitter.com/argyleink
[3] https://twitter.com/piccalilli_
In addition to yourself, there are other people in other situations who are looking for different kinds of content.
With a podcast, though, I can listen while I do dishes or whatever, and hopefully that will at least give me enough background information that I can understand the written parts more quickly.
I love this podcast + text approach in theory. A podcast to talk through the material, and a really well written page to reference. The CSS Grid page is a great example of this.
Aside: As someone who has been in web dev for a while, sometimes I feel like what I need is an "unlearn CSS" tutorial, to erase some old habits.
Screenshot: https://d.pr/i/gvj3fA
I've been trying to visit web.dev for days for various reasons, but I just get this and neither Chrome nor Safari will let me visit. But apparently a bunch of you can see the page, so I'm confused as to why I seem to be the only one seeing this... but maybe you or someone there can help? Thanks.
Perhaps you have a proxy causing interference?
As the sibling comment notes, looking at the certificate using Advanced may help clarify things.
Update: here's the full chain that I see:
web.dev, signed by GTS CA 1D2, with a root certificate of GlobalSign Root CA - R2.
As far as I know, I have no proxies to interfere...
If you can open your terminal, this may be easier:
% openssl s_client -connect web.dev:443
It will hang (I guess awaiting more commands) but you can use Control-C to kill the connection.
The gist below has the first several lines showing what you should see.
https://gist.github.com/macintux/68ab1317d4b7677951069baf95c...
Glad you got it sorted, happy to help.
[1] https://github.com/GoogleChrome/web.dev/tree/main/src/site/c...
Checked out the first two chapters on this resource and immediately recommended it to my colleagues as well.
The section about layout starts with: "In the early days of the web, designs more complex than a simple document were laid out with <table> elements. Separating HTML from visual styles was made easier when CSS was widely adopted by browsers in the late '90s." etc. etc.
This history lesson is not really relevant for newbies. It is basically a "you kids have it easy, when I was your age...", something which every generating find really tedious to listen to, since it is irrelevant for their current situation.
Knowing history is fine when it is relevant (e.g encountering legacy code), but it shouldn't be the first thing in a tutorial. Put it at the end or in a footnote or appendix.
I think it happens because writers tend to explain stuff in the same order they learned it themselves. But this is not always the most natural order to learn things for newcomers.
I disagree. Knowing the context and motivation behind why a certain technology was created is always helpful for learning.
I've run into so many situations while learning web development where a design decision seems like nonsense until later when I learn about the history of how it evolved. First example that comes to mind is the `===` situation in JavaScript.
And while backwards compatibility remains a concern for browser vendors, it's much less of a concern for web developers nowadays given the vast majority of users are using auto-updating browsers. Indeed, the purpose of this guide appears to be an explicitly "evergreen" guide to CSS, targeting only the feature set of modern browsers. If you're using grid, custom properties, conic gradients, etc. you're not writing backwards compatible code.
It is like using a screwdriver to knock in a nail because you don't have a hammer - better than nothing, but not what a screwdriver is designed for.
It's of course pedantic to discuss all this now as those days are thankfully long gone :D
As someone who made/hosted Web 1.0 websites, isn’t a software engineer, and has over the past few years tried creating/hosting websites again, things got a lot more complicated in the interim.
So I hear your perspective that it sounds like some old person is yelling get off my lawn. No one wants to hear that.
However, for someone like me who didn’t have CSS, the slight history lesson is helpful.
Basically, historical context helps to cool down natural negative reaction.
In answering questions from actual newbies completely new to this, I was a bit surprised at just how much I took for granted because I was around for the historical context.
If you're working on a new project that's true. If you're working on an old project, and bringing it up to date, then understanding the code that's there is very useful. That starts with understanding how things were in the past, and why people did things that might seem a bit crazy (eg spacer.gif).
https://github.com/w3c/csswg-drafts/issues/129#issuecomment-...
Sometimes new ways of doing things completely free us from the friction of the previous ways, and people who do not already have those scars have the advantage of being unrestricted by them
Hard disagree. Especially with technology, what we have today doesn't usually make much sense unless you compare it with what we used to have: everything started out the simple, but naive way, and evolved out of combat-tested lessons learned to what it is right now. If you don't know what those lessons were, a lot of the design decisions that went into what you see will seem mysterious and, possibly, pointless.
so folks know what we're talking about:
https://web.dev/learn/css/layout/#layout:-a-brief-history
It's four (pretty short) sentences that give a small amount of context pretty quickly and then links to another resource if you want to know more. I'd agree with you if it were a page or two's worth of history, but there's not much to find distracting here.
More importantly I think you're focusing on the newbies who are coming in with nothing but ignoring the newbies who are looking at existing code and a whole bunch of tutorials and stackoverflow answers out there written over the last two decades. Acknowledging that things have changed in CSS quite a lot in that time and pointing to where they can learn more means you don't distract the really new newbies much but you also don't confuse the other ones, leaving them with lots of questions ("but I read [this] about CSS...") and no idea where to look to reconcile some old advice ("use jquery for all styling!") with what they're learning now.
But it's also four sentences in the eighth chapter of a tutorial. It's not going to solve all confusion but it's also not a derailment.
I'm just saying: Don't put this up front in a tutorial.
Don't explain GOTO before explaining if-else blocks.
I find it similar to the use of acronyms. When an explanation introduces domain-specific acronyms I always ask what the acronym stands for. It's important to me because just memorizing key "ABC" and associating it with some kind of outcome forms a very weak bond in my brain. If I know what the acronym stands for, the bond is far stronger and larger pieces of the picture are revealed. Interestingly, I find that when I ask an explainer what an acronym stands for there's a couple classes of responses. In my experience, most are simply that the explainer doesn't know. And among those explainers, most don't care. But some will be curious and look it up. A few will know and you can tell that they find it important too. Fewer yet, will explain the definition when introducing the acronym and maybe even comment about its origins.
I'm guessing that these classes of people would also correlate closely to those who prefer turn-by-turn directions vs a route on a map with the full context of other routes in the area.
Think about when you're learning to work on a legacy system. You (hopefully) don't just learn the current state of the system in a vacuum. You go through and learn the history of decisions and constraints that got it there, the layer upon layer of changes that resulted in the end result in front of you.
I do. This really puts things into context for me. If I don't get that when learning something, I will look for the answers later. So I'm very happy when it's right there to begin with.
It tells you just the right amount of things you need to know to be productive. https://reactnative.dev/docs/flexbox
It's not React Native specific. It works for web-based CSS as well.
And this for grid: <https://cssgridgarden.com/>
A lot of people think of CSS as if it’s not code itself. Modularize it and create patterns like you would for any other piece of code(ie. react components), and it becomes fairly straight-forward to do things that would normally take 100+ lines of code in JS, in just a fraction of the time and code.
There are definitely a lot of times where Javascript makes sense, but what I really just wanted to point out is that people usually default to 'Well I'm already writing tons of Javascript, I may as well write more!' as an excuse to create simple animations or transitions with dozens, or hundreds of lines of code, or bringing in a dozen external dependencies to handle it that also break in weird ways. I'm definitely not a NoJS zealot either -- I've been working primarily with React code full-time in production systems since 2014. But over time I've found CSS to be far more pleasant and faster to work with than testing, maintaining, and/or relying on someone else to do the same thing in JS.
As an example, one of the most basic components I can think of is an accordion. You simply can't make one that works in a visually pleasing way (the way most people would expect!) in CSS because you can't animate to or from `height: auto`. The best you can do is some cop-out technique of fading out or squishing the content with `transform` and then having the content that follows it do an immediate jump up/down.
Instead, animating an accordion that actually animates the layout around it smoothly absolutely does require JavaScript, to tell CSS what non-auto values it needs to animate to and from.
And that's just the most basic component I can think of!
Another example: anchoring one element to another, when those elements don't have a parent-child relationship. Think tooltips. This requires JavaScript to measure the anchor element's position on every goddamn frame and keep the other one in sync, when the layout engine already has all the necessary information and could easily be built into CSS.
Well yeah, you can't do it in pure CSS because you can't do most things in pure CSS. The HTML element you're looking for is "details." (this seems to be one a lot of react people miss.)
You a moment ago:
> half the stuff things like React are used to do could be accomplished much better with a small amount of CSS
you now:
> yeah, you can't do it in pure CSS because you can't do most things in pure CSS
Take this CSS accordion which uses hidden form elements: https://codepen.io/raubaca/pen/PZzpVe
I agree that if you want to use HTML semantically *and* have intuitive UX/UI, you're very limited in what you can do without Javascript, but this isn't *just* a failing of CSS; rather, I think it's due to the design of HTML and CSS historically being to the exclusion of the other, rather than with a symbiotic relationship in mind. Go far enough back into the history of web standards and it kind of makes sense though; HTML and precursors had been in development for years before CSS was standardized
The reason the animation appears to work in the example you link to doesn't actually have anything to do with the form elements or semantics – rather, it's cheating by animating the `max-height` of the tab content from `0` to `100vh`.
This can be done just as easily without all the form stuff, but it's a bad solution to the accordion animation problem, because (1) it assumes that accordion content will never exceed the height of the viewport (what about on phones in landscape mode? you're only talking a few hundred pixels there), and (2) CSS will ease between the actual minimum and maximum values without regard for where the element's true height actually stops changing, i.e. it will animate from 0 to 100vh in the duration requested even if the height only ended up being like 20px and thus visually stops changing 5% of the way into the transition – so whatever duration and easing you specified isn't actually being rendered in the way that you wanted. If you specified an `ease-out` for example (starts fast, slows down at the end), you'd just get a super fast linear-looking transition that ends much quicker than you planned and never has the slow easing at the end (because CSS is actually still transitioning the `max-height` property which is no longer having any effect on your element that's much shorter than the max-height).
That being said I’d rather use CSS than the abomination used for styling in WPF.
For that, I strongly recommend "Flexbox Zombies" and "Grid Critters" by Mastery Games. They're good games, and excellent educational resources for learning CSS layout.
https://flexboxzombies.com/p/flexbox-zombies https://gridcritters.com/
I unironically love CSS and I once got a contract gig doing nothing but CSS for a PWA, because their front-end dev didn't want to or couldn't (can't remember) do it
Look at "Demos" to see what I mean (http://www.cssplay.co.uk/menu/).
I realize to actually get good at design requires elbow grease and practice, but it still would be nice to have a good teacher/guide to show you how things are done now.
As for what the designers do, it's mostly copying ideas from popular apps and tweaking it to appease the product people, who are requesting changes to appease leadership.
Perhaps Tailwind is another option? Use a system to make an MVP or wireframes, then get someone to pretty it up and give you a PSD, Zepplin or Figma link.
Or for a DIY angle look into 2D Design, Print design and Desktop Publishing. Design a business card, that kind of stuff is the old school of user interface. Typography is another hot one, studying communication is the key to getting good.
Are you building in a react environment? Are you building WordPress websites? Are you just building simple landing pages? Are you building in a team environment? These could all have different solutions, they could also use similar solutions.
But you need to decide how you want to think about CSS. Which to me, is atomic vs component driven.
Atomic is building small reusable classes, then use those classes everywhere in your HTML. It keeps things consistent. [Tailwind CSS](https://tailwindcss.com/) is the winner of this race at the moment. Lots of people are moving to it. There are solutions for standard CSS, SCSS, or even working with it in React type environments.
Component driven is how I think of BEM, "Block Element Modifier". Break things into reusable components, keep your naming structure consistent according to BEM specs.
I personally prefer BEM type of process (break your pieces into components), but with usage of utility classes also, these can be thought of as atomic (one use, like text-align: center;).
I'm going to try Tailwind on a project soon (I've been following it for years), but I will still think of it in a BEM type structure. Things get messy in atomic when you have complex UIs that have different needs across device sizes. I personally have a hard time looking at HTML when one element could have 10+ classes on it if you go pure atomic.
I've kept things consistent without Tailwind with my own set of config (for things like colors, units, font stacks, z-index stack, etc), then various helper functions for things like keeping breakpoints consistent.
There are lots of great resources (look up atomic css and BEM css), you should browse through many of them to get a well rounded picture of how people work with CSS.
But figuring out how you want to think about CSS and putting a system around it seems like where you are. I recommend trying various methods out, and see what works best for you. Just be flexible if you are in a team environment. A team sticking to a defined standard (even if it isn't your favorite) is better than lots of competing standards.
For me one of the keys to "getting" CSS, and I think is the hardest, worst part of CSS, is understanding all of the implicit contexts that are generated. For example, elements have positioning roots. Nowhere does this word even show up in the CSS language, you have to know that it's created whenever an element has a position that is not static.
Similarly elements have a stacking context which is hugely important to understanding z-index and transform. Again never explicitly mentioned, inststead stacking contexts are implicitly created by a variety of actions like setting an element's background color to anything with a non-zero opacity.
Developers (especially junior) think that if it looks right, that it is right, and they're done. But CSS is not just specifying how something looks, you are also very much specifying visual behavior, not just appearance. Content is dynamic, layouts change at different breakpoints, new elements come and go, another dev comes in and adds something later... you need to account for all of these things.
For example, a developer rotated an element using CSS transform because the library we were using only supported a horizontal layout and not a vertical one. Sure, everything looked right in isolation, but now this element doesn't play nicely with others, because transform only affects the visual position, not the offset position of the element, so all its siblings still think it's horizontal, and they're getting all jumbled together.
Or, using absolute position to, say, anchor a close button to the top right of an element. Sure, the way you did it happened to put it visually in the right spot, but it's not actually in the right spot according to the layout engine because its offset parent is not the element you're trying to anchor it to, so if other content gets put in there eventually, it will be in the wrong spot.
Or, they'll use `line-height` to add space around some copy, without thinking about how that text will now look when wrapped.
So in my opinion, any CSS tutorial worth a damn needs to hammer home that (1) just because it looks right doesn't mean it is right, (2) you can't really ever style an element in isolation, you need to think about how it interacts with its parent and sibling elements, and (3) elements actually have two different positions, one that you see, and a potentially different one for layout.
Knowing those things is key to understanding whether you've designed things "correctly" vs. something that just happens to look right in the moment.
(I've only skimmed this course so far, so I'm not sure whether it satisfies what I want. But I'm hopeful!)
I'm absolutely guilty of this one and would love to know the correct way to do it if you have a resource handy. I generally feel like working with CSS (or ideally Tailwind now) is an uphill battle. In my defense I would also give the container a padding which should (in theory) prevent any of its statically positioned children from overlapping. But as a full-stack developer I often feel like this is the domain of people who spend their entire career focusing on design, and generally when I'm working in this realm its because we don't have one of those people.
As an example, if your goal is for the button to appear over the right-side inner box ("hero content") here:
+-------------------------------------------+
|+----------+ +---------------------------+|
|| nav | | hero ||
|| | | (x) ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|+----------+ +---------------------------+|
+-------------------------------------------+
...then you should make that button either a direct child of that hero content (and give that container `position: relative` to make it the offset parent), or if that's not semantically acceptable, then add a new container around the hero content which will match its size/position and serve as the button's offset parent.Otherwise, if you just let the outer container be the offset parent because it happens to place the button in the same spot in the moment, then later when more content gets added to that container, you'll end up with this:
+-------------------------------------------+
|+----------+ +---------------------------+|
|| nav | | header ||
|| | +----------------------(x)--+|
|| | +---------------------------+|
|| | | hero ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|| | | ||
|+----------+ +---------------------------+|
+-------------------------------------------+
...where the button is no longer over the correct box, because it was never anchored to it correctly in the first place (instead, it was anchored to that outermost container).Thanks for the detailed response
That said, what has replaced SASS? I'm struggling to find a preprocessor that allows nesting/grouping etc. Or is that built into CSS by now? Being able to nest CSS was a game changer for me in terms of css organization.
If you are in an environment where you have 0 control over how the HTML is structured I can see where long selectors are helpful, but when you do have full control over the HTML they are a huge anti-pattern.
In other words, I like nested CSS when I have a nested structure on the page. Then each class relates to one thing, and I can maintain continuity of the outer containers (say) as I change the inner ones.
In the old days, we didn't have column inside of content inside of page inside of ..... We just had whatever we had and css nesting wasn't as logically congruent with the structure.
Now, though, we have hugely nested pages (which stinks, but whatever), including a lot of inline-written CSS and the only way to get to it is long selectors. I agree it's an anti-pattern.
But you can have nesting and not require long selectors. And if you do need them for some god-forsaken reason, they are easy to find from a SASS structure.
.element {
&__title {
color: red;
}
&__subtitle {
color: blue;
}
}
which compiles down to: .element__title {
color: red;
}
.element__subtitle {
color: blue;
}
There's a lot of (valid) criticism that this makes code harder to grep, although if you structure things well it's still easy to find via the base element class. BEM and approaches like this in general tend to require a lot of discipline and organization to pull off effectively.CSS wants you to write:
.element.title { color: red; } .element.subtitle { color: blue; }
Any technique that depends on discipline and organization has already failed.
People scoff at CSS-in-JS and atomic approaches like Tailwind (although Tailwind seems to get a lot of support around these parts now!), but I've really come to see the value in side-stepping these issues entirely.
CSS has absolutely 0 knowledge of your BEM hierarchy, they're just different names as far as its concerned. The developer has just chosen to pretend that a hierarchy exists where there is none.
CSS cannot do trees, but it can do logical AND and OR, so you can somewhat express a hierarchy as a union of the different levels of your tree, so
.button.login.green has a logical meaning in CSS where .button__login--green is no different than using .pinapple as a class name.
Same here. This also happens in other fields; my brother is a journalist, and most newspapers (here in Norway at least) fired most of their photographers when the industry suffered due to online papers not generating as much money. They thought it's easier to learn a journalist how to take pictures, than the other way around. I feel that most people who create webpages think similarly, i.e. it's easier to make the programmer learn how to create a good design + CSS etc. than learning a designer how to program... Both newspapers and webpages have suffered from these ideas I think; but money talks...
The place I have the most trouble is getting content inside a flexbox to fill the box, especially when making a single screen app where I want various "panes" and I want the content inside to fill those panes.
For whatever reason I still haven't completely figured it out and it's always trial and error. Sometimes I need a "min-height: 0" and other times it seems like I need a "height: 100%;" and a maybe a "position: relative;"
I wish (I should probably write this myself), I wish there was a way of specifying the areas and their constraints and then have that translated into the appropriate CSS.
How to appropriately size text. No -- for the 1,000,000th time -- I will not use Modularscale, which feels obtuse to me. Using some formula on a website that someone says works also feels arbitrary. Not to mention that the SASS implementation hasn't been touched in years.
With Grid, I felt like it was the first time I saw someone create a layout where it was obvious what was going on. I have yet to see something like this system - but for text sizing.
AFAIK, the best modern way to do it is `font-size: clamp(0.75rem, 1rem + 2vw, 3rem)` (the use of rem as well as vw is to not break zooming for accessibility)
Modern browsers handle zoom just fine, regardless of units. We use rem in case a user has set their own preferred base text size (the same reason we don't use viewport-relative units).
The thing that really made Grid sink in for me was seeing the pseudocode at Grid By Example [1], showing how each of the different constructs work.
[1]: https://gridbyexample.com
Jason Santa Maria's On Web Typography [2] originally included a "worked" example that you could put into a page and pull apart to start building similar things in your own projects. However, before it shipped, this section was dropped.
[2]: https://abookapart.com/products/on-web-typography
With calc and clamp now in the mix, it seems as if we no longer agree that 1rem=16px even if px is probably the most precise screen unit we have.
"Uh, pixels aren't responsive, so let's not even mention them."
It's not the end goal, but it feels like we're throwing away the map which could explain how to reach said goal.
Screenshot: https://d.pr/i/gvj3fA
I've been trying to visit web.dev for days for various reasons, but I just get this and neither Chrome nor Safari will let me visit. But apparently a bunch of you can see the page, so I'm confused.
W3schools have some but they are too simplistic.
Thanks for publishing it!
I understand a proper parser would (perhaps) be more complex, but could also be open sourced in a lower level lang such as C, and then used by everyone, there's also already the full test suites for testing the output - maybe even Google+MS+Moz could open a contest - "fastest, most readable and efficient parser in C (or rust, wtv) takes 10k home"
Just a happy user
For my own homepage i did not write a single line of css.
I am very, very bad with CSS and can't wrap my head around it, but tailwind allowed me to create a very pretty, responsive homepage with very high lighthouse scores (bought tailwind UI too).
Congrats, you now know CSS! It sounds like I'm joking but honestly, Tailwind is essentially composable shorthand for CSS with a design system applied. If you grok Tailwind, you understand the concepts of CSS, you just might not know the full names for all the properties and values.
I do unterstand the basic ideas behind CSS, but is just cant apply it. Tailwind allowed me to apply it.
If i could, i would prefer to write CSS! After 10 years i have given up though.
Personal anecdote, I understood how flexbox works only after using Tailwind for a personal project.
Tailwind might be nice, but most projects will require in-depth knowledge about CSS.
Go on Twitter and look at the Tailwind community - they see CSS as a doomed, awful language and Tailwind as the thing that makes it pleasant. They're not CSS developers. They're people actively trying to avoid being CSS developers.
JavaScript? no
There is a learning curve, but if you assimilate the language, by doing a project or two, you won't have to even look at the documentation for doing your designs.
Tailwind replaces having to come up with a new semantic class name every time you need to style an element only to realize the actual semantics you picked were completely wrong.
Tailwind is basically a cleaner way to do everything as inline styles.
Tailwind doesn't make you copy and paste, it moves the reuse of styles out of CSS which sucks at managing reuse into whatever HTML building system which likely has some concept of reusable views.
Then they make `.box` and include it as a mixin. Like CSS developers have done for a decade (and which tailwind itself does using PostCSS)
> Tailwind doesn't make you copy and paste
Yes it does. Moving all styles into individual elements without reuse is copy and paste.
Tailwind all but assumes you will be using something that allows you to extract HTML into components, be that something like React or Vue, or classic partials in a server-side templating language like Twig. You reuse the entire component, rather than just the CSS, which IMO is far better aligned with how apps are actually built.
So no, using Tailwind classes is no more copy pasting than typing CSS in full into a separate stylesheet is copy pasting.
Login box and messages are separate components, but they share padding metrics, border styles, a palette, etc.
Have you used tailwind before?
My argument is that using the “mr-1 pl-2” utilities on both a login box and a message would be no more copy pasting than creating a stylesheet with “.login-box { margin-right: 0.25rem; padding-left: 0.5rem; }” and “.message { margin-right: 0.25rem; padding-left: 0.5rem; }”.
And if you’re suggesting that you would create a single CSS class with those properties to apply to both the login box and the message, then it’s my opinion that that is a broken abstraction that falls apart as soon as your designer asks if you can make the spacing in the login box a little looser.
I'd say that's underselling it. For one thing it keeps you within a design system. By default you're given spacing that works in increments of 0.25rem, a handful of colors, etc to work with (which can be replaced/extended) so you have to go out of your way to break the design system that's in place.
Also inline styles don't allow for hover, focus, @media, etc. Which were always a pain in the ass with normal CSS anyway. Using Tailwind was the first time I didn't find writing a responsive UI to be a giant hassle. You just design for mobile and then for anything that needs to change on bigger screens you put a sm: or lg: or whatever breakpoint style and you're done.