.../articles/
Small to Mid-Sized CSS Architecture on the Assumption of Scoped Styles

Small to Mid-Sized CSS Architecture on the Assumption of Scoped Styles

2019.09.30

Premise

This is based on the conditions we usually work under in projects, as follows:

  • Uses Nuxt.js. Targets small-to-medium-sized web service (site) build projects.
  • CSS is basically written as scoped inside Vue files.
  • Normalize/reset CSS and the like are loaded via config, etc.

This article doesn't get into how to split components — that's a rabbit hole deep enough on its own.

What is HTML

Philosophical questions like this can feel vague and there are many opinions, but I want to go back to basics, so here's a note. HTML is structured text, and structure carries meaning. The only thing you need to keep in mind is that HTML's role is not to assemble a puzzle out of divs.

  • Avoid using divs and spans that have no structural meaning (avoid using them purely for decoration)
  • Use the elements redefined in HTML5 — section, main, nav, figure, etc. — to place elements semantically
  • Fewer elements is generally better (though it depends on the case)

I think it's fine to use a div when you need one to wrap elements. In fact, limiting div usage to that purpose makes it clearer what each div is for.

Let's write it simply

"Write it simply" might sound difficult, but it may be easier to picture if you think of it as writing explicitly and plainly. Note that stripping out information ≠ writing simply.

What matters most is whether someone other than yourself can understand it. "Understandable to others" could be rephrased as "it's clear where each thing is written."

It might also help to keep the following in mind.

Do you misunderstand the DRY principle? - Qiita

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

A concrete approach

So how should you actually write it? Let's go through some concrete examples.

  • Give each section a unique class (think of it as naming a component)
    • As much as possible, the name should be understandable on its own
      • Good example: names like hero, news that clearly convey their function or role
      • Bad example: names like information1 that depend on ordering or don't convey their role
  • Naming under a section can generally just use common nouns
    • Under News, clear class names like .list or .item are fine
    • That said, structure your SCSS properly and use the child combinator >
      • Structuring SCSS this way is an important point for keeping it readable
  • Try to keep the order in which you write classes consistent with the HTML side
  • It helps to have a rule for the order you write things in: properties for that class → media queries for responsive support → child elements, and so on
  • Even if similar properties recur, don't turn everything into a mixin
    • Prioritize explicitness over saving effort
    • Conversely, for things like color and font specifications, use variables to avoid inconsistency in notation
<!-- Example: a two-column layout below the hero area, showing news and embedded SNS -->
<template>
  <main class="cout-wrap">
    <section class="col-wrap wrap-center">
      <div class="hero col-lg-10">
        <h1>Lorem Ipsum</h1>
        <p>Lorem Ipsum is simply dummy text. </p>
      </div>
    </section>
    <section class="col-wrap wrap-center">
      <div class="news col-lg-5">
        <h2>News</h2>
        <ul class="list">
          <li class="item">
            <div class="date">YYYY.MM.DD</div>
            <div class="title">newstitle</div>
          </li>
          <li class="item">
            <div class="date">YYYY.MM.DD</div>
            <div class="title">newstitle</div>
          </li>
          <li class="item">
            <div class="date">YYYY.MM.DD</div>
            <div class="title">newstitle</div>
          </li>
        </ul>
      </div>
      <div class="sns col-lg-5">
        <h2>SNS</h2>
        <div class="twittermodule">
          <iframe>...</iframe>
        </div>
        <div class="facebookmodule">
          <iframe>...</iframe>
        </div>
      </div>
    </section>
  </main>
</template>
/* Structure of CSS written inside scoped */
.hero{
  > h1{
    hogehoge
  }
  > p{
    hogehoge
  }
}
.news{
  > .list{
    > .item{
      > .date{
        hogehoge
      }
      > .title{
        hogehoge
      }
    }
  }
}

Classes like .cout-wrap, .col-wrap, and .col-lg-10 are for layout. I'll cover those in a separate article, so let's skip past them here.

There are also places where properties are applied directly to HTML elements, but the idea is to add classes freely where needed. This makes maximum use of the benefits of scoped. I know there's a strong opinion out there that common nouns shouldn't be used as class names, but by using scoped together with the child combinator, we keep the scope of influence contained.

How to share common styles

There's the question of what to do with classes you want to share across components, but in my view, this ultimately ties back to the question of how to handle Atoms in Atomic Design. As you break components into layers and load each one, the leaf-level components end up being little more than a bundle of style properties. A button component at the Atoms level, for example, really doesn't do much beyond specifying styles.

For properties like that, it seems best to create classes and load them globally. Turning them into Vue file components is also clear, but for small-to-medium projects, going too far with componentization tends to add more burden than it saves.

Things to avoid

The following are anti-patterns — some pretty basic mistakes I've noticed while doing reviews.

  • Don't write properties applied to the same class in scattered places
  • Don't use property names like width or flex as class names
  • Don't use abbreviations
    • Things like info, which I tend to use myself too — stop using it
    • Same goes for btn
  • Don't create classes whose meaning is unclear
    • Don't use class names like mini_info
  • Don't use class names like sp, tb
  • Use :nth-child or :first-of-type only for a list of identical elements
    • Don't use them to target elements with different roles based on their order within a parent element
  • Avoid having to write the same thing over and over
    • Avoid writing the same thing repeatedly for each device width in media queries

This time, I focused on CSS design for small-to-medium-sized projects. I also referenced articles like the ones below. Comparing OOCSS, BEM, SMACSS, FLOCSS, and RSCSS to find the design philosophy that suits you | Black Everyday Company

A summary of ECSS's overview and approach - Qiita

I'm not a fan of overly verbose class names, so I'd like to digest these ideas in my own way and put them into practice. If you have any thoughts or feedback, please feel free to share.

written by

.../article/

Articles

All articles

From Firebase to Vercel, Contentful to microCMS — a migration log written with Claude Code

From Firebase to Vercel, Contentful to microCMS — a migration log written with Claude Code

We moved our corporate site's hosting and CMS, and made it bilingual along the way. The constraints we only found by running against real data were more useful than the migration itself, so this post focuses on where we got stuck.

Can't Read POST Data with Firebase Functions × Remix?

Can't Read POST Data with Firebase Functions × Remix?

How to read POST data from a Remix action when running on Firebase Functions.

Generative AI for Executives and Leaders: An Approach to Self-Driven DX

Generative AI for Executives and Leaders: An Approach to Self-Driven DX

Building a structure where executives and leaders themselves can identify issues and evaluate solutions using generative AI. We introduce how combining this with our hands-on support dramatically improves both the quality and speed of digital transformation.

Deploying a Monorepo Next.js App (App Router) to AWS Amplify

Deploying a Monorepo Next.js App (App Router) to AWS Amplify

Notes on the obstacles we hit while deploying a Next.js app managed in a monorepo to AWS Amplify.

Keeping Production Running Smoothly with Remote Work and Online Meetings [Documentation]

Keeping Production Running Smoothly with Remote Work and Online Meetings [Documentation]

Many production companies have adopted remote work as a result of the pandemic, and we are one of them.

Designing an E-Commerce Site That Sells: How to Find Great Reference Examples

Designing an E-Commerce Site That Sells: How to Find Great Reference Examples

There is no single formula for e-commerce design that sells. Driving revenue requires a solid concept, and getting to that concept requires thorough research.

Productivity Tools We Recommend as a Production Company, Including Services That Work Well Solo

Productivity Tools We Recommend as a Production Company, Including Services That Work Well Solo

With remote work becoming the norm during the COVID-19 pandemic, our team now works from home most days of the week.

We Released Thought Recorder, a Figma Plugin for Keeping a Commit History of Your Designs

We Released Thought Recorder, a Figma Plugin for Keeping a Commit History of Your Designs

We hope this helps web designers who work in Figma. Read on for how to use it.

How to Build an E-Commerce Site, and Which Platforms We Recommend

How to Build an E-Commerce Site, and Which Platforms We Recommend

Shopping online for fashion, appliances, and even groceries is now routine. With the pandemic accelerating the shift, we receive a steady stream of questions about which platform to use and how much it costs.

Generating FastAPI Schema Classes from OpenAPI

Generating FastAPI Schema Classes from OpenAPI

We chose FastAPI, a relatively modern framework, for a Python API project. FastAPI can generate an OpenAPI definition from your backend code, but here we do the opposite: generating FastAPI schema classes from an OpenAPI definition prepared in advance.

View all articles

Contact us