Blog

#development

#css

Something non-designers understandably struggle with is how to make things look good. One of those things is long form content that’s well set and readable. Luckily, CSS makes this easy, you just have to know what to change. That’s exactly what we’re going to teach you in this article.

Set Studio

So many good tips in this article from Andy Bell. I’m using many of them already on this site. Long-form content can be hard to format, so if you need some help, tap the link above!

Scroll Snap for a Nice Mobile Experience

Small enhancement to homepage. Two column layout, so mobile normally would make that one column. Which it had. But I write a few featured posts and lots of “other” posts. The sidebar had the “other” posts, but that got put way down the page. You’re unlikely to get there through scrolling. But putting it first wouldn’t make sense because then the featured posts are too far.

So… I made a scroller using the new scroll-snap CSS functionality. Now you can see the latest “other”, but it doesn’t push the featured posts down 3 scroll heights.

.b--article-list {
	display: flex;
	width: calc(100vw - 64px);
	overflow-x: scroll;
	scroll-snap-type: x mandatory;
	scroll-padding-right: 20%;

	> * {
		min-width: calc(80% - 32px);
		padding-left: 32px;
		scroll-snap-align: start;
	}
}

With scroll-snap-type set to x mandatory, we allow card-based scrolling horizontally. Setting the scroll-snap-align to start for all children makes the snap point the left side of each card.

I have implemented this style of interface before, almost a decade ago. It took a lot of JavaScript. Now with just a few lines of CSS, you get a super interactive little component.

Demo: Homepage view on mobile or scale down and you’ll see the Ramblin’ section using the above.

Clamp for Truly Responsive Typography

CSS’s clamp() has been around for a few years now, but I finally got to use it in the rebuilding of this site. Let’s look at the hero text block on my new homepage!

:root {
  --font-size--dynamic-headline-3: clamp(21px, 4vw, 36px);
  --vertical-spacing-5: clamp(36px, 8vw, 72px);
}

.b--homepage-hero {
  max-width: 60ch;
  margin: 0 auto var(--vertical-spacing-5);
  font-family: Parkly, sans-serif;
  font-size: var(--font-size--dynamic-headline-3);
  text-transform: uppercase;

  & p {
    color: rgb(0 0 0 / 60%);
    text-align: center;

    & strong {
      font-family: "Parkly Wide", sans-serif;
      color: rgb(0 0 0 / 75%);
      text-transform: uppercase;
    }
  }
}

I’ve got the two variables included too. Okay, so the Dynamic Headline 3 variable is defined as clamp(21px, 4vw, 36px). Minimum, preferred, and maximum. The browser then makes the decision for us. Now one has to be mindful of that middle. It can be a somewhat arbitrary relative value if your clamp is tight, but if you have multiple headlines of varying sizes— like any typographer is going to— you need to make these numbers proportionate. Let’s look.

:root {
  --font-size--dynamic-headline-1: clamp(43px, 8vw, 72px);
  --font-size--dynamic-headline-2: clamp(32px, 6vw, 54px);
  --font-size--dynamic-headline-3: clamp(21px, 4vw, 36px);
  --font-size--dynamic-headline-4: clamp(21px, 3.1vw, 28px);
  --font-size--dynamic-headline-5: clamp(21px, 2.65vw, 24px);
  --font-size--dynamic-copy: clamp(16px, 2vw, 18px);
  --font-size--dynamic-small: clamp(14px, 1.78vw, 16px);
}

Dynamic Headline 2 is 50% larger than Dynamic Headline 3. That applies to the min, pref, and max. But at the smallest sizes, Dynamic Headline 3, Dynamic Headline 4, and Dynamic Headline 5 are all the same. They got too small otherwise.

As we allow our pages to be more fluid with dynamic grids, flexbox, and clamps, we have to let go of some of our pixel precision in design. Almost all the fonts— and vertical spacing!— on this site are dynamic with clamp(). The header, I think, is the only thing that isn’t.

Organize Your CSS with Stylelint

A few years ago I was on a new project at work as the frontend engineer. In code reviews I would recommend reordering of CSS properties, as many of us have a preferred order. One of my teammates pointed out that she would never remember my order and thus wouldn’t likely follow it, so I should find a way to automate it.

Stylelint and Stylelint Order enter chatroom.

As I have become accustomed to over the years, most JavaScript engineers are very familiar with ESLint. If you aren’t, please go research and use it. It cleans up your code, makes it consistent, and helps when you are on a larger team than just you. But, frankly, it even helps when it is just you. JavaScript allows chaos. Semicolons are optional. ‘Nough said. What engineers often don’t even think about is linting their CSS. Many don’t consider CSS a “real language,” but that is a different conversation.

Stylelint is exactly what you would expect if you’ve worked with ESLint. I use the stylelint-config-standard to start. This handles most things. I turn off a few items. The biggest part of my config is the custom ordering of properties using stylelint-order.

As you can see below, I separate my properties into groups (eg. display, grid, dimensions). This means position: absolute; is followed by top, which just makes sense. width and height are right by each other. Alphabetical and other sorts work for different people for different reasons, but logically sorting by type of property just keeps me sane.

The nice thing about this is if your run Stylelint, it’ll throw warnings on all things out of order. But, you can run Stylelint with --fix and it will reorder your properties for you.

I bring this with me on every project. The one below is from this very site. A couple days ago I got ESLint and Stylelint working against Astro— I’m used to using it in React projects. I then fixed over 400 linting issues and now feel a peace knowing my code is consistent.

/* You'll need the following packages: stylelint, stylelint-config-standard, stylelint-order */

{
  "extends": "stylelint-config-standard",
  "plugins": [
    "stylelint-order"
  ],
  "rules": {
    "length-zero-no-unit": [true, {"ignore": ["custom-properties"]}],
    "property-no-vendor-prefix": null,
    "custom-property-pattern": null,
    "selector-class-pattern": null,
    "selector-id-pattern": null,
    "at-rule-no-unknown": null,
    "no-descending-specificity": null,
    "order/properties-order": [
      [
        {
          "groupName": "display",
          "properties": [
            "content",
            "appearance",
            "position",
            "top",
            "right",
            "bottom",
            "left",
            "z-index",
            "display",
            "flex",
            "flex-direction",
            "flex-basis",
            "flex-flow",
            "flex-grow",
            "flex-shrink",
            "flex-wrap",
            "align-content",
            "align-items",
            "justify-content",
            "justify-items"
          ]
        },
        {
          "groupName": "grid",
          "properties": [
            "grid",
            "grid-area",
            "grid-template",
            "grid-template-areas",
            "grid-template-rows",
            "grid-template-columns",
            "grid-row",
            "grid-row-start",
            "grid-row-end",
            "grid-column",
            "grid-column-start",
            "grid-column-end",
            "grid-auto-rows",
            "grid-auto-columns",
            "grid-auto-flow",
            "grid-gap",
            "grid-row-gap",
            "grid-column-gap",
            "gap"
          ]
        },
        {
          "groupName": "dimensions",
          "properties": [
            "width",
            "max-width",
            "min-width",
            "height",
            "max-height",
            "min-height"
          ]
        },
        {
          "groupName": "margin and padding",
          "properties": [
            "margin",
            "margin-top",
            "margin-right",
            "margin-bottom",
            "margin-left",
            "padding",
            "padding-top",
            "padding-right",
            "padding-bottom",
            "padding-left"
          ]
        },
        {
          "groupName": "border and background",
          "properties": [
            "box-sizing",
            "border",
            "border-top",
            "border-right",
            "border-bottom",
            "border-left",
            "border-width",
            "border-radius",
            "outline",
            "box-shadow",
            "background",
            "background-color",
            "background-image"
          ]
        },
        {
          "groupName": "font",
          "properties": [
            "font",
            "font-family",
            "font-size",
            "font-style",
            "font-weight",
            "line-height",
            "color",
            "text-decoration",
            "font-smoothing"
          ]
        }
      ],
      {
        "unspecified": "bottom"
      }
    ]
  }
}

View Gist on Github

Two years ago when Web Tools was released, CSS Grid was not supported in its current form by any browser. Now it is supported by all of them. But, in my opinion, unlike most features of CSS that have come before, Grid needs some good tooling around it to help ease work with it in development. So I have started to work on some tools to help with Grid and along the way, I have been dabbling a lot with Grid.

Below is a basic experiment: reproduce the layout of the new App Store on iOS. Along the way, I also found good use for CSS Custom Properties — Variables. I hate that they aren’t called variables. — in setting the background of articles, the background and text color of the text block on each, and more.

CSS is getting more and more powerful. But, along the way, it is getting more and more simple. Where old layout techniques (tables, floats, flex box) were truly ill-suited for layout, CSS Grid is 100% made for layout. So go, dabble with Grid. Grab a comic book and reproduce the layout. Or a poster from the 70’s. Learn the ins-and-outs of it because this is the future of where front-end web development and web design is.

I’m opinionated. If you’ve worked with me or hung out with me for any period of time, you know this. I’ve been building for the web since 2001, before JavaScript libraries, before CSS, before Web Standards. That is a lot of years of experience and with it, one learns a few things. The Standards movement was a major thing just as I was getting started freelancing. jQuery was just coming about as I entered and assisted in teaching a JavaScript class in college. Responsive Web Design was coined and defined as I started my first role at an agency in Chicago.

One learns a few things.

Of the last few years, I have pushed hard against using jQuery. Simply put, most browsers have solid support for new technologies that emulate many of the great features of jQuery. Those native features do it faster, better, and require less code. Remove jQuery and you remove 30+kb of resource load.

I have pushed against Bootstrap. It is a large beast of a library when most sites that include it use it for a grid system and not much else. A grid system can be written in less than 100 lines of CSS that’ll achieve the needs of your site specifically, so why include 200+kb of resources?

I have pushed against WordPress. It’s not good for the developer and offers a not-great experience for the client. There are better CMSs.

So this Summer and Fall, I decided to dabble.

I hadn’t built a website on WordPress in many years. The last one I built was before ACF took off. So I built a client a site in WP and I didn’t hate it. Much of what I have said against WP remains true. Especially after launching a large site on Craft earlier this year. But, for what it does well, it does well. Build a couple of custom plugins was a breeze. ACF made storing complex data from two third-party sources easy and displaying it easier.

I have never used Bootstrap but always maintained that it is best suited for prototyping and administration panels. So as I started building an admin panel for a current project, I decided to try Bootstrap. And I didn’t hate it. There are parts that I won’t touch. The grid system is actually one of them. The spacing utility classes, while useful if you are not writing a lick of CSS, are another. But, the component structure isn’t far from something like Atomic CSS and is actually a welcome thing for the needs of the project. Unfortunately, it requires that the page resources weigh over 300kb, which means I will likely scrap Bootstrap in a few weeks and rewrite with my own CSS.

We must, as developers, not become set in our ways and get dogmatic about certain things. There are things that we should be more opinionated about than others. I wasn’t necessarily wrong with either WordPress or Bootstrap. But, now that I have worked more with each, I can see the lure of them when it comes to getting something done quick and dirty. Atop that, I now have a more solid argument against some points of them.

So if you haven’t dabbled with something in a while or at all, maybe try. You may learn a few things.

But the core principles and mechanisms [of CSS] are no more complicated than they were a decade or even two decades ago. If anything, they’re easier to grasp now, because we don’t have to clutter our minds with float behaviors or inline layout just to try to lay out a page. Flexbox and Grid (chapters 12 and 13, by the way) make layout so much simpler than ever before, while simultaneously providing far more capability than ever before.

Eric Meyer

I built my first couple of layouts with Grid over the last weeks. Hot dog. Things that would have taken me forever with floats took me just a couple lines of code with Grid. I’ve been using Flexbox for a while, to the point of mostly knowing the syntax, but Grid is a brand new beast.

It is astonishing that we have, for almost 20 years of CSS, never had a native layout system. Now we do. Instead of complex (and large) libraries like Bootstrap, we can now do complex layout with simple syntax. Hell, we can do far more complex, asymmetric and two-dimensional layout with Grid that we would never consider doing before. A renaissance in web design is coming. But are front-end developers up to snuff?

The subtle difference between progressive enhancement and graceful degradation is lost on too many. Many of those that support “mobile first” don’t support progressive enhancement, which is an oxymoron.

Mobile first is progressive enhancement. Start with the most important part of any site: content. Mark it up. Semantically. Why? Because some readers experience your site without CSS. It’s true. Some just want the content. Screenreaders and search engines are the largest of these.

Then style the content. That’s the CSS. Mobile first says start with the LCD, the Lowest Common Denominator: mobile. But make sure that your CSS works in the LCD. That might be IE 9. It might be IE 11. Look at your analytics if possible. Progressive enhancement means add features when available. Progressively enhancing. You see? So if you are using a feature that is only available to IE 11 and better (Chrome, Firefox, etc.) and you need to support IE 9, make sure that the feature is not necessary for the user experience.

Then JavaScript. Understand that some have JavaScript disabled. Whether it be over-cautious IT departments, search engines that cannot handle rendering and parsing JavaScript, users with bad network connectivity that fails to load it, or most importantly screenreaders that help those with handicaps consume the content of the web. JavaScript is an enhancement. So long as you have the last two components set, your page works fine when JS is turned off. So, as features are available, use them.

But see, too many developers these days have abandoned this methodology that fueled the Web Standards movement. Instead, sites require over 300 kilobytes of JavaScript libraries and don’t load anything if JavaScript is disabled. Instead of starting with content, they start with jQuery, Angular, React, or whatever the library de jour is. Everything is built in JavaScript. This is graceful degradation, start with the Greatest Common Denominator. Except many aren’t even testing for the LCD. They aren’t turning off JS to make sure that their site will work for those that disable JS. Often they even break the most basic components of the web browser: the URL and the back/forward buttons.

We need to get back to progressive enhancement as the standard. We need to get back to the promise that the web is accessible to all, no matter the device they use.

When every new website on the internet has perfect, semantic, accessible HTML and exceptionally executed, accessible CSS that works on every device and browser, then you can tell me that these languages are not valuable on their own. Until then we need to stop devaluing CSS and HTML.

Mandy Michael

Preach! It’s all I see these days in job descriptions. JAVASCRIPT! Ninja preferred. Rockstar acceptable. And then they produce crap frontend code. Their HTML and CSS is restricted to Bootstrap at best, custom crap with style attributes all over the place at worst. When I was their age, the emphasis of frontend was on the other side of the triangle: HTML and CSS. Without these, your JavaScript means nothing. Even if you are embedding your CSS and HTML in your JavaScript. Shudder.

Remember faux columns? I just did equal-height columns with flexbox yesterday. The old days sucked.

Now if we could just convince the kids to stop putting HTML and CSS inside the JavaScript…