
CSS: The bad bits and how to avoid them - jofo25
https://www.joeforshaw.com/blog/css-the-bad-bits-and-how-to-avoid-them
======
ars
There's nothing wrong with styling on an id.

You could put the style right in the HTML tag, or on the page where it's used,
but with dynamic pages (and static stylesheets) both options will cost you
bandwidth.

And they split up your styles into separate places.

So putting the style on the id is the right thing to do, and I don't
understand why the author is against it.

If I need my footer to look a certain way, then #footer {} is exactly what you
should do.

Not add some bogus class based style just in case someone decides we need two
footers on one page.

~~~
mattigames
There is not a single time I had though to myself "This should have been an ID
instead of a class"; but there are hundreds of times where I have though to
myself "This should have been a class instead of an ID".

~~~
sametmax
Well if what you style is the main content/header/footer area, and there is
should only be one of it per page, using an id is a good way to enforce it as
well as document it.

If you made it a class, I would assume I can reuse it elsewhere.

Now it's ony true for stuff you can't reuse, but unless you are building a
boostrap competitors, there are actually a lot of things you never reuse in a
real website.

~~~
reificator
Once I needed to make an internal IE addon to listen for certain elements
being selected on pages outside of our control. (to ensure we never collected
sensitive data for compliance reasons, long story. Trust me it makes more
sense in context than it does in a single paragraph.)

My co-worker wanted to grab by id and attach listeners, but I was convinced
that wouldn't work. I wanted to listen at the top level and filter down by
id/class/etc...

The first production test was <redacted>.com/login. It had a login widget on
the navbar and a login widget in the main content section. Both the username
and the password field had the same id in the navbar and the content. So the
addon did the right thing on the navbar, but not in the content, and we had to
go back and redo it thanks to id reuse.

My point is, elements with ids are rarely unique. I've never regretted using a
class instead of an id. I've regretted using an id instead of a class. And I
really regretted third parties using ids instead of classes.

Please don't use ids. Your unique elements won't be for long, I guarantee it.

~~~
setr
A friend once told me about a girl in their cs 101 class, who learned about
arrays, and proceeded to make every variable an array. When queried, she
responded, "I might end up realizing I need a multiple of the variable, and
this way I won't have to change anything when I do".

~~~
reificator
Did she then go on to create jQuery? Because that concept (with a touch of
functional inspiration) is one of the underlying ideas behind the library and
why it was considered so much easier to work with than the DOM API.

I get where you're coming from, but I don't think it's a good reason to avoid
classes. That's what they're there for.

------
romaniv
Never understood why people prefer verbose and repetitive BEM classes over
custom properties and appropriate CSS selectors.

    
    
      <div class="my-block my-block__my-element my-block__my-element--my-modifier">

becomes

    
    
      <div my-block="my-element my-modifier">
    

This solves for specificity, and uses built-in CSS features instead of a
"manual" workaround.

~~~
jmsuth
This isn't a realistic example of how you should use BEM, you would never have
a block, element, and modifier in one class. The "block" class would be used
in a div that wraps the elements:

    
    
        <div class="block">
            <div class="block__item">
                I am an item
            </div>
            <div class="block__item block__item--danger">
                I am a dangerous item
            </div>
        </div>
    

Your simplification relies on an HTML hack and can potentially be more
confusing when modifier names start colliding.

~~~
jrobn
Yuck. I would follow the advise in this blog post [1].

[https://www.smashingmagazine.com/2013/08/semantic-css-
with-i...](https://www.smashingmagazine.com/2013/08/semantic-css-with-
intelligent-selectors/)

------
drinchev
I'm a huge fan of 1 & 2, so I end up using CSS with only class names.

This helped me deliver maintainable and reliable stylesheets that other devs
like.

Most importantly using only class names you will gain :

1\. Your HTML / CSS is easier to maintain.

2\. Is faster to develop.

3\. Is faster to refactor.

4\. Is more portable.

5\. Is faster for the browser.

I even wrote a blog post about it [1].

[http://www.drinchev.com/blog/css-with-only-class-
names/](http://www.drinchev.com/blog/css-with-only-class-names/)

~~~
wvenable
But your HTML is uglier.

~~~
naasking
So? The only people looking at your html classes are you and your team. Bots
don't process css, and most people don't look at html.

~~~
wvenable
The same people looking and working on the CSS are the same people looking and
working on the HTML. HTML full of long complex class names is a bit harder to
grok.

I actually prefer nice semantic HTML but I admit that's not always possible.

~~~
naasking
> HTML full of long _complex class names_ is a bit harder to grok.

I wouldn't recommend long and complex names either, but with something like
tachyons, they're not long or complex, there are simply long lists of
orthogonal classes.

------
dfabulich
The advice to use CSS variables to handle Z-index confusion is a good first
step, but IME that's only the right way to handle global z-indexes like modal
lightboxes and menus. For local z-indexes, you should also know how and when
to create a new stacking context with position: relative.

This is the go-to article I send to newbies struggling with z-index.
[https://hackernoon.com/my-approach-to-using-z-index-
eca67feb...](https://hackernoon.com/my-approach-to-using-z-index-eca67feb079c)

~~~
mozumder
CSS Flexbox and CSS Grid allows one to reorder elements to avoid Z-index
problems as well.

------
tomduncalf
Using CSS-in-JS to enforce component-local CSS (and also allow easy dynamic
updating of styles, by making a “getStyles” type function) is the best thing
to happen to styling for a long time in my opinion. Recently I’ve been using
the “styled components” pattern (using the Emotion library) and despite being
initially sceptical, have found it really nice to work with.

So much more logical to write and maintain than plain CSS for a site of any
reasonable complexity. You can still apply global styles where they make sense
(e.g. styling all body text) and making use of JavaScript patterns for reusing
common chunks of styling feels much more robust than the CSS equivalent.

As someone who can do CSS but doesn’t do so that often, I can confirm that
it’s getting better with things like Flexbox and Grid, but it is still full of
maddening quirks! I do have a lot of respect for people who are CSS experts.

~~~
kaishiro
As someone just dipping my toes into some Preact, I’m still a but confused
about the styled components pattern. If you already have, say, a menu
component in an es6 class, with its own methods and helpers and render func -
how do you convert that to a styled component. All of the examples I’ve found
just spin up new buttons pre-wrapped in Styled, etc

That’s my only real sticking point here.

------
Kequc
I've heard about BEM many times and been forced to use it on a lot of
projects. It seems to be reasonably commonplace I was hoping for some smaller
tips so here's one I use very often.

Vertical height of text comes up a lot in CSS. It seems many people do not
make liberal enough use of the line-height property. Line height is a magic
bullet when you need some text to take up the correct amount of space.

With it, and your element styled to inline-block, of float left, or however
you are using it. You are able to modify the font size later on without having
any effect on the element's surroundings. It's also automatically centered
vertically and you can change it without much effort.

Not enough people using line-height.

------
peterchon
In my opinion, most CSS bad bits are a byproduct of bad use, not a problem of
the language(?) itself.

SASS, BAM, OOCSS, etc are all good practices. You can/will abuse those as well
without proper understanding and planning.

~~~
Someone1234
> In my opinion, most CSS bad bits are a byproduct of bad use, not a problem
> of the language(?) itself.

I've seen far too many bad languages come and go to believe that anymore.
People used to say that about PHP and VB6 too.

PHP eventually stopped with the "only bad programmers use me badly" and grew
up, and VB6 died. A win in both cases.

CSS could be far better; and bad practices won't disappear until doing it the
right way is easier than doing it the wrong way.

~~~
talmand
The ability for good practices is already there, just too many people would
rather complain about their bad practices to bother learning the good
practices and blame the language.

~~~
sharpercoder
-it is not possible to decrease scope

-tooling is hard e.g. to detect unused styles

-scope problems are a pain to debug

-some constructs are awkward (e.g. tooltips with :before and positioning styles)

-vertical text behaves unexpected wrt box model

-variables are suboptimal

There are probably a lot more.

~~~
talmand
1\. I require more of an explanation as to what you mean by decrease scope. I
could interpret that in different ways.

2\. Sure, I understand the discipline necessary to prevent that is difficult
in a team setting. I would say that likely at reaching that point something
went wrong before then. That seems a tooling problem, not a language problem.
How many languages provide features out-of-the-box that assist with
discovering unused code without some form of third-party exploring that space?

3\. In what way? What scope problems? I can think of several bad practices
that lead to scope problems. I can think of examples of two people following
two different best practices creating such problems.

4\. I know it's not exactly a fair thing to say, but I don't have those issues
with the example you provide. I'm sure there's plenty of examples of showing
how to do it.

5\. Flex. But, granted, old practices didn't handle vertical issues well
because originally HTML wasn't intended for that.

6\. In what way? Do you mean variables from a pre-processor or CSS custom
properties?

I'm sure there are more, just like almost all languages have their quirks and
issues that make it difficult to address if not understood. Do you have any
other examples that we could discuss? Are there any specific use cases where
you are having difficulties that I might be able to help out with?

------
difosfor
I'm surprised nobody mentioned using the Shadow DOM yet. That provides you
with a very good means of scoping your CSS; e.g: within custom elements. Just
look at Polymer.

------
yoran
For z-indexes, we're using a slightly an approach that I find a bit clearer:

    
    
      $some-element-z-index: 1 + max(
        $other-element-z-index,
        $should-be-below-z-index
      );
    

This way the relationship between elements that should be below or above is
more explicit.

In my head, it works a bit like a spreadsheet. You update the z-index value of
an element somewhere below, and all the z-indexes that depend on it update
their value too.

------
bluetwo
I tend to write CSS for projects by hand without a pre-processor, borrowing
from previous projects only when called for.

One of the things I've been doing recently that helps debugging a lot is to
group the attributes within a css class into three, separated by a line.

1) Things that control where the item shows up.

2) Things that control the overall appearance of the item, like size and
background.

3) Things that control appearance of things within the item, like font color.

~~~
Siilwyn
That sounds a lot like the 'concentric order'. Can sort like that
automatically: [https://github.com/Siilwyn/css-declaration-
sorter/blob/maste...](https://github.com/Siilwyn/css-declaration-
sorter/blob/master/readme.md#sorting-orders)

------
pg_bot
There is a different and IMO better way to solve the global scope problem in
CSS. Adapted from the Paul Irish method of executing JS you can use data
attributes to conditionally write CSS. For example a new user controller would
output the controller and action names as data attributes on the body. I then
have a separate css file under `assets/users/new.scss` which only contains css
for that page. Your Sass code looks something like:

    
    
      [data-controller="user_controller"][data-action="new"] {
        .header {
          background-color: blue;
        }
      }
    

This method keeps you organized and completely removes the biggest problem
most people have with CSS.

~~~
sebazzz
If we're going that way, you might as well include that particular file only
on that page.

~~~
pg_bot
I would rather have one single request for a large static asset, than multiple
small requests for per page based css. In my experience CSS files typically
fall in the range 50-100KB. I'd rather not have to pay the perf penalty every
time I load a new page considering the typical file size.

~~~
no_wizard
For what its worth, this is no longer the case with HTTP/2, which is up and
coming for most sites (I hope). I imagine in a few years time this will be
gone with the wind (hopefully).

see
[https://docs.google.com/presentation/d/1r7QXGYOLCh4fcUq0jDdD...](https://docs.google.com/presentation/d/1r7QXGYOLCh4fcUq0jDdDwKJWNqWK1o4xMtYpKZCJYjM/edit#slide=id.g518e3c87f_0_318)

and

[https://medium.com/@asyncmax/the-right-way-to-bundle-your-
as...](https://medium.com/@asyncmax/the-right-way-to-bundle-your-assets-for-
faster-sites-over-http-2-437c37efe3ff)

------
no_wizard
I have been writing a lot of CSS (well SCSS) lately and this seems like a good
time as any (though I admit somewhat off topic) about a question I have
regarding the newer Combination & Multiple selectors
[https://developer.mozilla.org/en-
US/docs/Learn/CSS/Introduct...](https://developer.mozilla.org/en-
US/docs/Learn/CSS/Introduction_to_CSS/Combinators_and_multiple_selectors) and
Attribute Selectors [https://developer.mozilla.org/en-
US/docs/Learn/CSS/Introduct...](https://developer.mozilla.org/en-
US/docs/Learn/CSS/Introduction_to_CSS/Attribute_selectors)

This stems from the fact that I have inherited the task of re-writing a very
large (at least for one person, I feel) task of re-writing an internal
framework that is really gotten too burdensome to add anything to. I have been
contemplating instead of trying to get crazy with a ton of different selectors
where you end up with a pattern like this:

``` .selector .selector1 li, .selector .selector1 li a { some-style: some-
value; } ```

Which I find A little crazy compared to something like this:

``` [class*="selector selector1] { some-style: some value; } ```

or my person favorite:

``` ul > li > a { color: blue; } ```

While these examples are I think very simplistic (I don't wanna junk up the
page with tons of stuff) I've met alot of resistance to this idea, and
splunking other frameworks for inspiration (Shout out to
[https://bulma.io](https://bulma.io) ! I like their work, its really wonderful
FYI.) I don't see alot of this.

While the resistance I've met from others who have some input on this project
(and rightly so, they're also part of our stellar in house design team) seem
to resist this idea, but haven't articulated why.

I was wondering if it comes down to: is there actually an issue with using
these heavily vs some of the older semantics or, which I feel is quite
possible, people have done things for so long one way its hard to see another
way?

While its seemingly less verbose sometimes (not always) I feel like the new
selectors give you a way to combat specificity problems by controlling when
context around your classes is better than having ton of different classes and
nesting those over and over.

Am i missing something?

~~~
jacobwilliamroy
Generally you would want to avoid descendant and child selectors. With rules
like

    
    
      ul > li > a
    
      .selector .selector1 li a
    

The system will check ALL anchor tags and move left until it has completely
matched the rule. This makes the above selectors extremely expensive
(perfomance-wise) and can cause slow page-loads. Tag selectors and universal
selectors are generally a bad idea for this same reason.

And using inheritance to select elements indirectly is actually better for
performance than directly selecting the inheriting elements. For example, if
you want to set typography for an entire page, instead of selecting all p and
h1 tags, just select the body tag.

Here's a link to a more in-depth explanation of all of the above with
examples:

[http://mdn.beonex.com/en/CSS/Writing_Efficient_CSS.html](http://mdn.beonex.com/en/CSS/Writing_Efficient_CSS.html)

~~~
esprehn
The good news is all modern browsers use a Bloom Filter to quickly skip over
elements that wouldn't match the descendant or child selector relationship.

You could probably construct situations with very deep selector relationships
and thousands of matching elements where the ancestor walking adds up but the
other costs of computing style often end up being more important than the
selector matching in many scenarios. Not that you shouldn't aim for simpler
selectors of course.

(Usually the problems with expensive selectors come from side effects of
dynamic changes to the document. ex. Some selectors will make the browser
recompute hundreds of elements when only changing something small because the
browser isn't tracking that relationship in a precise way.)

~~~
no_wizard
Hmm so what’s consensus then? Avoid these types of selectors when at all
possible or no?

------
majewsky
> Often there’s an argument to use tags to create a default set of styles. For
> most sites, it’s usually a good idea. However, if you’re just overriding
> those styles pretty much everywhere, I’d say don’t bother. Put them in
> generic utility classes (e.g. .paragraph, .heading-1, etc) and use them as
> you need.

Please don't. Tags have semantics for important reasons. Even if you're
removing one of those by overriding the default styles, the semantics of tags
are still used e.g. for screenreaders. It's not a mistake that HTML 5 added a
ton of new semantic tags like <article>, <header>, <footer>, <aside> and
<nav>.

~~~
totallymike
I think the argument is against adding rules to tags to create a default set
of styles, not against using semantic tags throughout the page.

If my understanding is correct, the argument is to use

    
    
      <style>
        .my-article {
          background-color: fuchsia;
        }
      </style>
      <article class="my-article">...</article>
    

rather than

    
    
      <style>
        article {
          background-color: fuchsia;
        }
      </style>
      <article>...</article>

------
dsego
One bad thing about CSS is cascading. Too bad that's the main thing. Some
styles like colors and fonts move like a plague into every nook and cranny,
all children elements get infected. Others like border get applied only onto
the targeted element. Heavily nested selectors is another one, good luck
overriding a style on a bootstrap element, their selectors strictly follow
html nesting levels. You want to override a td style by a adding a class, you
mean .table > tbody > tr > td.yourclass. Ugh. Sass only helps you write even
more convoluted CSS if you don't know what you are doing, it's like C and C++.

~~~
RobertRoberts
> _One bad thing about CSS is cascading._

This is an odd statement, considering that the C is CSS is "cascading". Maybe
it's a perspective issue, because I really enjoy the cascading part of CSS.
Don't you think it's better that we _don't_ have to set a color for each
element/child element individually?

~~~
dsego
I know C in CSS is cascading, that doesn't make it a good feature. I think
it's one of the big reasons that the web is slow and bloated. CSS is
needlessly complex, no wonder it takes herculean efforts from browser vendors
to keep up with the exploding complexities [1].

[1][https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-
en...](https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-
quantum-css-aka-stylo/)

~~~
talmand
One reason for the cascading is to reduce bloat. If the CSS is bloated because
of cascading and/or needlessly complex then the CSS and/or design is wrong,
not the cascading.

------
amelius
Just like WASM allows us to implement new languages as alternative to
JavaScript, could it one day become practical to implement an alternative to
CSS?

EDIT: Perhaps by implementing the whole browser in WASM? Would that even make
sense?

------
mephitix
CSS Grid really helped me understand/wrangle z-index and stacking contexts.
For example, within a grid you can use grid-row/grid-column to position an
overlay over a grid item. The z-index will be scoped to that stacking context.

Modular CSS I think is a huge step forward - I totally agree that global scope
is killer. As much as people love to hate on CSS-in-JS, I enjoy using styled-
components a lot. I've noticed since using it I've been composing CSS instead
of inheriting or overriding styles.

------
breeny592
I think tooling is coming a long way to help with these - take for instance
BEM. CSS modules is a great way to avoid needing BEM, as the bundler is
handling the uniqueness of the classname for you (during minification etc.).

This is just the nature of web development - almost every tech in the stack is
flawed, but tools and best practices make some sanity out of the chaos.

------
cratermoon
Best workaround for all the problems of the class discussed in the article:
stop trying to be pixel-perfect.

------
z3t4
Add another class to make your element more specific. You can have many
classes in one element! Then you never have to use !important again.

    
    
      .rabbit.drivingACar.onIce.withRocketBoosters  {
        color: pink; /* pretty specific */
      }

------
xab9
Shadow dom and proper scoping (whichever popular method you chose for that) is
a god send. I really dislike BEM though, we have files that have more
classnames than content and tags combined :D

------
Risord
Just wondering how much more complains and valid critique against css is still
required to get real alternative.

[https://ishoudinireadyyet.com](https://ishoudinireadyyet.com)

~~~
RobertRoberts
I hope never enough, CSS is a fantastic language. Also, houdini won't replace
CSS, it's actually the opening up of the CSS engine:

[https://developers.google.com/web/updates/2016/05/houdini](https://developers.google.com/web/updates/2016/05/houdini)

~~~
talmand
I agree since most of the complaints and critiques of the language that I've
seen are from people who don't appear to know how to code it correctly.
Especially the complaints along the lines of "this is how it works in language
X, it doesn't work that way in CSS therefore CSS sucks!" and other similar
notions.

------
talmand
Bad bits? More like code correctly, use already existing CSS features to your
advantage, and use common sense when naming things. Then the so-called "bad
bits" tend not to happen.

------
stefanchrobot
I'd add one thing: avoid multiple classes on a single element; use mixins to
avoid duplication. I tend to do so even for classes that have some toggle
state, i.e. .some-class-active.

~~~
Blahah
does this have a performance benefit or are you recommending it for the code
clarity?

~~~
esprehn
It'll increase your parse and network transfer time (gzip might help there
though) in exchange for reduced selector matching and style computation time.
How much that matters probably depends on your content, how big the document
is, how much CSS you have and how many classes you're using.

If you're talking about the difference of:

.a { ... } .b { ... } .ab { ... }

<div class="a b"></div> <div class="ab"></div>

It's probably not going to matter a lot. It's two map lookups vs one, and some
associated overhead. Probably better to optimize elsewhere. :)

------
maxharris
_Best workaround: Quit front end web development. If that’s not an option,
tough, you’ve got to use CSS._

Instead of quitting front-end dev, you might also consider using
[https://www.styled-components.com/](https://www.styled-components.com/)

Styled-components solves all of the issues the author highlights in his
writeup.

Bonus: styled-components works both on web and on React Native! So you don't
have to throw out all your stuff to participate in the post-browser future...

------
soperj
>If you told any back-end developer that they had to use a programming
language that gave all variables global scope, made every object’s internal
state visible, let any other developer override their code, they’d probably
resign on the spot

Isn't that the case with Javascript?

~~~
zdragnar
Nope. A variable is only global if you are in non-strict mode and leave off a
`var` on the declaration, or explicitly assign to the global scope (aka window
in the browser).

Object internal state is generally true, if you're using prototypal objects.
Use function closures when you need to internalize something.

Speaking of which, anything hidden via closure is truly hidden and can't be
overridden. Anything public can be overridden, excepting objects frozen via
the ES5 spec's Object.freeze method.

I generally enjoy most aspects of JS, and generally detest working with CSS,
in large part because I delegate interacting with many browser APIs to JS
libraries, whereas there's no escaping the awfulness that is years of
backwards compatibility with incompatible vendor specs and CSS
implementations.

I suspect I'll be happier once CSS Grids are universally supported (properly)
among all of the browsers I need to target, and use postcss for the rest.

------
TheSisb2
Use CSS Modules imo.

------
hoosieree
Keep going!

    
    
        z-index: 2147483647;

~~~
expertentipp
//[FIXME] Workaround for the component in IE

z-index: 2147483648 !important;

------
guylepage3
Stop using CSS and go with modular SCSS

~~~
RobertRoberts
> _Stop using CSS..._

Maybe I am stupid here, but doesn't SCSS just render out to CSS?

~~~
poxrud
For me the best thing about scss is the ability to nest selectors. This makes
your code a lot easier to read and more organized. Of course having functions,
mixins, extends is also nice.

Saying scss is pointless because it outputs regular css is the same as saying
that es6 is pointless because it can be represented as regular es5.

~~~
RobertRoberts
> _...es6 is pointless because it can be represented as regular es5._

Let's be reasonable, that's more like comparing CSS 2 to CSS 3. :P

Everything I've read and discussed with others in the industry, SCSS seems to
be useful for far large projects with many designers and programmers stepping
over eachother. I work for a smaller company, and we build very clean CSS, and
would not benefit at all from SCSS.

Recently a friend at another medium sized company switched to SCSS "because".
Seriously, it was one designer that liked one feature from some library that
required some build tool that required SCSS... So they all have to learn SCSS
now. No other reason.

------
magic_beans
The world really doesn't need another "What to Avoid with CSS" list.

This list also assumes the use of a CSS pre-processor.

~~~
commandlinefan
Well, I liked it. I had never heard of BEM before, either, so I'll definitely
take a look at that. What gets me about CSS is that, in spite of having used
it now for about 20 years, I still don't have an intuitive feel for it. With
everything else I work with, I start out with an experimental approach: if I
change this, I see this, if I change that, I see this other thing; after
usually a few weeks of experimentation, I develop an intuition for it so that
I can usually predict what it's going to do before I have to see it do it
(admittedly it took more than a few weeks to get to that point with Lisp and
assembler). CSS, though, just seems to deny intuition; even after reading the
O'Reilly "CSS: The Definitive Guide" book, I don't have the faintest clue what
my CSS is going to do until I try it out.

~~~
interfixus
Hear, hear! Working exclusively in scss, maintaining orderliness and decent
discipline, and having - like you - been at it for close on twenty years, I
still keep a constant wary eye on my output screen, I still get regular
surprises there, I still rely on the browser dev-tools, and I sorely miss the
3d representations they used to have, at least in Firefox.

I have learned to simply accept css for what it is: An unholy legacy kludge we
have to live with. Just don't let's speculate on the millions and millions of
wasted man-hours over the years.

