Indie Web Guide
Indie Web Guide - Basic CSS
In this guide, we learn to style HTML!
If you are new to HTML/CSS, please refer to the Introduction Guide before continuing. We also recommend reading the Basic HTML guide as well.
Basic CSS
In the last guide, we covered the very basics of HTML files, structure, tags, and attributes. Now, let's talk about CSS, or Cascading Style Sheets. This point probably gets brought up in a ton of guides, but the term "cascading" is very important to not losing your mind while writing it.
Alright, back to the actual CSS. In the cascade, style definitions or "rules" flow down from the top. Sometimes, the top is not exactly obvious, but the flow has something called "specificity." What that means is, depending on how specific the targeting of an element is, that rule usually wins above all others.
You don't need to worry about this now, but bear in mind that the more specific the targeting is, the less likely it is to be overridden by another style unless it's just as or more specific.
Before we move on, lets talk about where CSS even lives. There are three places you can create CSS rules:
- In HTML inline
styleattributes. - In a
<style>tag in the<head>of your page. - In a separate
.cssfile located where your HTML can find it, also added into your<head>tag.
For this example, lets create a style.css file next to our index.html file in the project folder.
You can import this file in your HTML <head> tag with a <link> tag.
Example:
<head>
<link rel="stylesheet" href="style.css">
</head>
Or, if you prefer, you can just create a <style> tag in the same place:
<head>
<style>
/* CSS goes here */
</style>
</head>
So, I mentioned "rules" a bunch, what are CSS rules? CSS rules/definitions/blocks, whatever you want to call them, are just that. They are blocks of properties you define to link what styles go to which elements via "selectors."
Selectors are the way you target elements in your HTML document. Selectors can be as simple as the name of the element itself, which will fortunately/unfortunately target all elements with that same name. Sometimes, this is what you want. You can apply a base style to all <button> elements, for example, by using the button selector.
Example:
button {
background: red;
}
If you want to get more specific, you can apply class or id attributes to an element, or both! Classes are targeted with a period (.) and IDs, similar to HTML, are referenced with a hash/sharp/pound symbol (#).
Let's try out some selectors. You can create a <div> with a class of "target-me":
<div class="target-me"></div>
And select it in CSS with a period followed by the class name (.target-me):
.target-me {
/* styles for elements with "target-me" class */
}
This makes sure that only elements with the class of target-me will be affect by the styles within.
I don't want to drag out the section on selectors, but it becomes very important very quickly, so I will try to get through this fast.
You can combine different selectors to make more complex targeting. If we look back at the previous example, the CSS is targeting any element that has the target-me class, but what if we only want buttons with that class...? Simply add the element name, immediately followed by the class name, with no spaces: button.target-me.
This essentially tells CSS "only target button elements that directly contain a class of target-me." So, you can give any other elements the target-me class, and they won't be affected by styles provided to button.target-me rules.
Targeting can get a little deep, and we will get more advanced in the Intermediate Web sections, but another couple of basic selectors you may use often are:
button p {}- Would target all paragraph tags within the button element, regardless of how deeply nested they are.button > p {}- Would target only paragraph elements that are an immediate child of the button element.button, p, a, div {}- Would allow you to target all of these elements under a single ruleset.
You don't need to follow this, but a new thing to CSS that may come in very handy (if you don't really plan to support very old browsers) is nesting! Previously, you had to combine selectors to target specific child elements, like having rules for button & button p. Now, you can add the button p rules like this:
button {
/* button styles */
& p {
/* styles for any child paragraph */
}
}
The & symbol is a stand-in for the previous selector. In this case, button.
So, how do we actually apply styles? (This is where it gets more fun!)
CSS has a ton of properties that allow you to control nearly any aspect of the elements in your site. There are a few exceptions, like certain form elements, but most things can be customized to your liking.
Some common properties are:
width/max-width/min-width- The respective width limits of the element.height/max-height/min-height- The respective height limits of the element.padding- The inner padding of an element.margin- The outer margin (gap/space around) of the element.color- The text color of the element.background/background-color/background-image- The background of the element.border- A line around the edge of the element.border-radius- The roundness of the corners of the element.position- How the element fits into the page flow.display- The layout style of the element.font-family- Replaces the current font with a specified font.font-size- The size of the element text.opacity- The opacity of the element.transition- The element property transition options for state changes.animation- The CSS@keyframesanimation applied to the element.
There are a lot, so as usual, feel free to read-up on additional properties on your own!
To start creating rulesets, you just need to apply these properties to a targeted element with property-name: value; syntax. The trailing ; is required:
<button class="test-button">Test Button</button>
.test-button {
padding: 4px;
background: skyblue;
transition: all 150ms ease-in-out;
&:hover {
filter: brightness(75%);
}
}
or
.test-button {
padding: 4px;
background: skyblue;
transition: all 150ms ease-in-out;
}
.test-button:hover {
filter: brightness(75%);
}
What we just did:
padding: 4px;- Adds 4 pixels of padding to each edge of the button to the text inside.background: skyblue;- Sets the button background color toskyblue.transition: all 150ms ease-in-out;- Transitions all element properties over 150 milliseconds with a smooth in-out animation curve.&:hovercreates a nested ruleset for when the button is hovered by the mouse cursor.filter: brightness(75%);- Applied a brightness adjustment filter that reduces (darkens) the overall element brightness to 75 percent of the original value. Applies to all child elements.
Don't worry too much about the specifics of the properties I haven't explained yet. We still have some stuff to cover to make sure you understand where we're getting these values and why.
So, padding has a value of 4px, which I just kinda chose arbitrarily. There are tons of CSS units, from virtual units, like: px (pixels); to real-world units, like: in (inches) & cm (centimeters); to relative units like % (percentage), em/rem (based on font size), vw/vh (viewport window width/height).
Once again, don't let the amount of options scare you off. Once you get the hang of the context, you'll find it pretty easy to choose a unit to fit the use case, especially as these guides go on and we get into more advanced subjects.
Colors also have quite a few formats that you can choose from, here are a few with an example of red:
- Name -
red- A named CSS color value. Full list - Hex -
#FF0000or#F00- A 3 or 6 hexadecimal value to define the red, green, and blue values. - RGB -
rgb(255, 0, 0)- Direct red (0-255), green (0-255), blue (0-255) values. - HSL -
hsl(0, 100%, 50%)- Hue (0-360), saturation (0-100%), and lightness (0-100%) values.
We've talked a lot about units, now let's take a break and do something a bit more fun.
Let's update our .test-button to be a bit more stylized. First, due to how text line-height works, we typically need to either set the line-height property to make the padding look more even, which can cause other issues, or we can can simply adjust the padding to accommodate the inner text better.
Buttons are often seen with a bit more horizontal padding anyway, so let's just adjust that property. Padding supports multiple syntax values:
padding: <all-sides>;
padding: <top-bottom> <left-right>;
padding: <top> <right> <bottom> <left>;
It's kind of a confusing pattern, but you can just try to remember that you start from the top and go clock-wise. Also, counter-intuitively, you may notice that it does not follow the XY pattern in geometry for the two-value option. It must be the top/bottom value first, then left/right.
We can set the padding to 6px for the top and bottom, and 8px for the left and right. So apply either: padding: 6px 8px 6px 8px; or padding: 6px 8px; for short.
Let's also try applying a new font to the button. Buttons are an element that does not automatically use (or "inherit") the global font. That value must be set explicilty. If you'd like to make sure all of your buttons use the current global font, simply create a rule for all <button> elements, like: button {font-family: inherit;}.
For our test button, I'm going to apply a different font called monospace. It is a default monospace-style font, typically used in terminals (or code editors).
I'm going to swap out the background color for deepskyblue and set the text color to white to make it easier to read.
I also want to add some borders, but I want to make them seem lit from a certain direction, so it will require some different rules than just border: <width> <style> <color>;. To set individual border edge colors, you can target properties like border-left-color to... set the left border color. Unfortunately, this means we'll need to create four new rules to accomplish this:
border-top-color: aliceblue;
border-right-color: blue;
border-bottom-color: darkblue;
border-left-color: lightblue;
This will make the top and left edges light blues, and the bottom and right edges dark blues, giving the button some vague appearance of lighting from the top left.
For the hover state, lets replace the filter rule with a new background color. I'm going to pick a lighter blue blue color: background: lightskyblue;. I'm also going to add a new property we haven't talked about called transform.
Transform allows you translate (move), rotate, and scale the element without affecting page flow. I want the button to grow slightly larger when hovered, so I'll apply transform: scale(1.05) to scale the button to 105% of its original size. Scale also has a few variants, like scaleX(), scaleY(), etc.
To end off this button example, I'd also like to add rules to the active (pressed) state. These styles will apply only when the button is clicked or held down.
We'll do what we've done prior, adding border that give the appearance of lighting, but to give the indication that it has been pressed inward, we can just flip the border edge colors by redefining them in a .test-button:active {} ruleset.
I'll gloss over this one a bit, but we need to apply:
background: dodgerblue; - Darker blue background.
border-top-color: darkblue; - Swapped with bottom border colors.
border-right-color: lightskyblue; - Swapped with left border colors.
border-bottom-color: aliceblue; - Swapped with top border colors.
border-left-color: blue; - Swapped with right border colors.
transform: scale(.95); - Scales the button to 95% of it's original size.
After all of this, we should have some rulesets that look like this:
.test-button {
padding: 6px 8px;
font-family: monospace;
font-weight: bold;
background: deepskyblue;
color: white;
border-top-color: aliceblue;
border-right-color: blue;
border-bottom-color: darkblue;
border-left-color: lightblue;
&:hover {
background: lightskyblue;
transform: scale(1.05);
}
&:active {
background: dodgerblue;
border-top-color: darkblue;
border-right-color: lightskyblue;
border-bottom-color: aliceblue;
border-left-color: blue;
transform: scale(.95);
}
}
or this:
.test-button {
padding: 6px 8px;
font-family: monospace;
font-weight: bold;
background: deepskyblue;
color: white;
border-top-color: aliceblue;
border-right-color: blue;
border-bottom-color: darkblue;
border-left-color: lightblue;
}
.test-button:hover {
background: lightskyblue;
transform: scale(1.05);
}
.test-button:active {
background: dodgerblue;
border-top-color: darkblue;
border-right-color: lightskyblue;
border-bottom-color: aliceblue;
border-left-color: blue;
transform: scale(.95);
}
From here, you can probably guess how to apply these styles to things like headers, sections, paragraphs, etc. We will, of course, go over more examples later on to help reinforce these concepts.
For now, you should understand the basic syntax of CSS and how to apply rulesets to selectors. Next, we go over basic JavaScript!