How I use CSS in practice
Published on
CSS, while not my strongest suit, is something I'm trying to actively get better with. I am by no means a "designer" or "visual artist", but I have developed some senses over the years that lend to my ability to know good from bad.
CSS is pretty much the opposite of coding in the sense that you create logic to automate and do away with the nastiness of doing things yourself. But it's not too different from a form of programming called Composition over Inheritance, where you describe properties for objects via traits or interfaces, instead of inheriting from a parent object.
The key groupings in CSS are based on Elements, Identifiers, and Classes. Element refers to an HTML element in the page, Identifier refers to a singular object in the page, while Class refers to many elements in a page.
-- CSS, but if it were Haskell
data Rule = Rule String String
data CSS = Element [Rule]
| Identifier Element
| Class [Element]
Recently I had a large HTML/CSS project, and it wasn't something I was totally amazing at, but I tried my best to learn some tricks along the way. Here I will share my insight into CSS that I have developed over the course of a few years.
Pretend you're designing a GUI program in C++ and Qt. How would you do it? You have an 800 pixel wide, 600 pixel high screen space. What do you do? You probably start by saying the first 50 pixels of your box are reserved for the File menu bar at the top. Then you start coming up with how you want to present your program. Data lists, buttons, interactions, a canvas for drawing displays, all that fun stuff.
This applies in CSS. If you're designing a web page, think about how you set up your screen space. If it's intended to be a three-column website, think of how evenly or unevenly you want the columns to be. 20/60/20? 10/70/20? Or maybe it's not even multiple columns at all, it's a single-column website.
The main thing to start getting used to in CSS is the idea of breaking things up into groupings of div
elements, and using that to create your visual space. It's a lot easier to break things down into rows than it is to break things into columns. Doing the reverse requires a bit of CSS manipulation to get it to display correctly.
Example: I use a mono-column website, as do many blogs. I prefer my navigation to stay at the top so it doesn't get in the way of the user. This is especially helpful when it comes to mobile responsiveness. Phone screens are a lot smaller, so multi-column layout websites become more complex when displayed on mobile devices. But if I keep my site mono-column, then it doesn't get in the way nearly as much.
The big thing that is hard to keep track of is how much space an element will actually have. Despite not being an object-oriented programming language with inheritance properties, CSS actually does pass information along from a parent element to the child. If the parent div
has a 300px wide screen space, then it's children know how long they can run until they hit that wall.
Let's start with the width
property, the one property everyone will use. It dictates how much space an element can run left and right on a screen. When this gets smaller, text and other elements will start to run out of space. The children of an element with a fixed width property cannot adjust it, or exceed it, but text can always be rendered in weird ways when approaching these limits.
Let's examine how we can make a mono-column website with only two CSS rules.
body {
width: 100%;
}
#column {
width: 50%;
}
<div id="page">
<div id="column">
<h1>My webpage</h1>
<p>Welcome</p>
</div>
</div>
The first rule for the body
takes on the inherited width from the browser window, which can be be variable depending on the dimensions of the browser. It can be 1000px or 100px, but the body
knows to use 100% of that space for the rest of the document. The #column
identifier says to use 50% width of it's parent, meaning it can compute on the fly how much space it has to work with. You can stretch the browser window to see this in action.
Sometimes that isn't going to cut it, because if you shrunk the window to 100px, only 50px would be available for rendering text. Instead we need to introduce more rules, like min-width
.
#column {
width: 50%;
min-width: 700px;
}
Now the #column
identifier knows it can allocate a minimum of 700 pixels for it's space. It will use the width: 50%
rule up until the space is too small, then defer to min-width: 700px
.
The space using percentages instead of flat pixel amounts can help a ton to create responsive websites, and also set up for when you want to build complex spacing. Pretend we did want to do a three-column layout, we can write that using a bit of percentages.
.multi-col {
width: %33;
display: inline-block;
}
<body>
<div class="multi-col">A</div>
<div class="multi-col">B</div>
<div class="multi-col">C</div>
</body>
Because there are multiple elements, we switch from an Identifer to a Class for CSS rules. This replaces the need to write three individual identifiers, cutting work by 2/3rds. We use a property for display
called inline-block
, which is able to display elements in the same group in an "inline" style instead of "block". Block typically means newlines are auto-applied when rendering, whereas inline will try to render all in the same line.
This is a lesson I had to learn when I needed it the most: combining multiple classes for sanity.
A lot of the times when I was doing text decoration, it's a lot easier to put rules into a class and call it a day, but the more properties a class has, the more complex and harder it is to share with other elements. Let's say you made a rule that large red text, but later on you had elements that you wanted red text, but not as large. What's the best way to go about that?
/* How do we cut down on rule clutter? */
.large_red {
color: red;
font-size: 24px;
}
.medium_red {
color: red;
font-size: 18px;
}
There are two mindsets we can see this issue as:
If we were to use multiple classes, all the properties get merged in together and will create a new invisible class ruleset. But the behavior here is where it gets unreliable. It isn't clear which class will have it's properties preserved when you merge classes, so to avoid rule collision, this behavior should not be counted on when creating web pages. If you used both large_red
and medium_red
, what will be the value of font-size
? It's not exactly clear.
Instead, it's easier to combine multiple classes that are good at doing easy tasks instead of doing large different roles in a class. Think about text coloring and decorations; you wouldn't want to define font size, color and decorations all inside one class. It would be more ideal to create separate classes that are easy to memorize while developing a page, then join those classes together.
.red_text { color: red; }
.yellow_text { color: yellow; }
.large_text { font-size: 24px; }
.sub_text { font-size: 10px; }
.underline { text-decoration: underline; }
While at first I think it seems silly that I'm using one-rule classes, it actually makes a difference in how I write HTML. I'm not constantly switching between <i><u><b><span style="color:x">
and instead using <span class="class1 class2">
instead. If I have a link I want to style, it's no different than how I style my actual text elements.
This one is going to be the last area I touch upon. In my case, I couldn't simply use an external library, but if I could, I might be keen to use Bootstrap or Tailwind instead. Responsive CSS designing is so dull and drab that I wouldn't wish it upon anyone realistically.
Media queries, the one way to check for certain conditions in CSS, is absolutely needed when it comes to making mobile-responsive elements. After all the careful consideration you may do for when picking out margin sizes, padding and indentation, goes out the window the minute your page is put on a phone. Suddenly you need to crank out all your elements to use the maximum space possible. You have to redeclare everything.
For instance, this will probably happen to you in the near future.
/* your carefully curated page, margins/padding and all */
#page {
margin: 0 auto;
padding: 10px;
width: 50%;
min-width: 600px;
}
/* now do it again but with way less */
@media only screen and (max-width: 600px) {
#page {
margin: 0 auto;
width: 100%;
}
}
The first part is a regular declaration block, while the second part is a conditional query to the media device to ask about certain properties. If the screen has a maximum width of 600, the new rules will be put in place instead, overriding previous definitions. So instead of including padding and a width of half the space, we instead tell our page to expand to the entire width, making sure to use as much screen space as possible.
This is the pain in the butt part because you have to carefully curate your elements and go through your entire web page a second time to ensure everything works properly. If you had ten elements for your page, you're going to have to create another ten rules to make them responsive, which means double the amount of effort you put in.
The only way you could try to avoid this is by using an additional overhead class to tag an element as a "mobile-friendly" kind of element. This is why composability is kind of cool sometimes.
/* empty because we don't want it to do anything normally */
.mobile100 {}
/* now write it's mobile query */
@media only screen and (max-width: 600px) {
.mobile100 {
width: 100% !important;
}
}
The !important
tag can be used in this way to override all other definitions in case of problems with multiple rule definitions. This is how Bootstrap and other mobile-responsive frameworks out there kind of operate, sometimes with more intelligence through the use of JavaScript APIs, but primarily through these kinds of tricks. You can also make some other mobile helpers for various widths as well.
This one is entirely optional depending on your project requirements, but a CSS compiler can go a long way in correcting mistakes for you, while also being able to macro-create some rules on your behalf. SASS, what I use on this website, can do a lot of heavy-lifting on your behalf if you let it, and comes with a wide array of extra functions you can utilize. Most importantly, it comes with variables, a huge upgrade.
Overall, responsive CSS is a hell of a journey to chug through, and these are some lessons I picked up along the way. Thanks for reading.