|
| 1 | +--- |
| 2 | +title: Styling with CSS |
| 3 | +template: splash |
| 4 | +--- |
| 5 | + |
| 6 | +The most important thing of any website is the content. Now that you've taken care of that with some HTML, you can turn to making it look a bit nicer. For that, you need CSS. |
| 7 | + |
| 8 | +Add the following line to link a CSS file to your page: |
| 9 | + |
| 10 | +```html title=routes/index.html ins={5} |
| 11 | +<!doctype html> |
| 12 | +<html> |
| 13 | + <head> |
| 14 | + <title>My website</title> |
| 15 | + <link rel="stylesheet" href="styles.css"> |
| 16 | + </head> |
| 17 | + ... |
| 18 | +``` |
| 19 | + |
| 20 | +And create the corresponding CSS style sheet file in the `routes` folder. (You could choose another name, but `styles.css` is fairly common.) |
| 21 | + |
| 22 | +```css title=routes/styles.css |
| 23 | +body { |
| 24 | + font-family: Helvetica, Arial, sans-serif; |
| 25 | + font-size: 18px; |
| 26 | + max-width: 30em; |
| 27 | + margin: 0 auto; |
| 28 | +} |
| 29 | +``` |
| 30 | + |
| 31 | +The above is a minimalistic style sheet, which applies four CSS properties to the HTML `body` element. |
| 32 | + |
| 33 | +Font-related properties (like `font-family`, `font-size`, `color`, etc.) are [inherited](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascade/Inheritance) by default, meaning that they will affect all descendants of `body` in the HTML document tree. However, this is the exception. Most properties are not inherited. |
| 34 | + |
| 35 | +For example, the `max-width` property is not inherited. It constrains the width of the `body` to not be wider than `30em`. An `em` is a relative unit and is equal to the font-size. Since the font-size of that element is `18px` (pixels), `30em` equals `30 * 18px`, which equals `540px`. Unless you work with a print designer who is used to absolute units like inches, centimeters and pixels, it's best to quickly forget again that the element is 540 pixels wide, as it doesn't really matter. Quite the contrary: it's good practice to use the `em` unit to specify things that should change if the font-size also changes – like the width of the text in this case. |
| 36 | + |
| 37 | +The final declaration in the above example is `margin: 0 auto;`. This sets `margin-top` and `margin-bottom` to `0`, and `margin-left` and `margin-right` to `auto`, which has the effect of centering the element horizontally. If you don't see that happening, try making the preview pane wider. |
| 38 | + |
| 39 | + |
| 40 | +## Header and Footer |
| 41 | + |
| 42 | +Most websites have a header at the top, main content in the middle, and a footer at the bottom. Let's add that. |
| 43 | + |
| 44 | +Wrap your existing content in a `main` element, indenting everything in it by two spaces. Then add the header before, and the footer after: |
| 45 | + |
| 46 | + |
| 47 | +```html title=routes/index.html ins={8-12, 15-22} |
| 48 | +<!doctype html> |
| 49 | +<html> |
| 50 | + <head> |
| 51 | + <title>My website</title> |
| 52 | + <link rel="stylesheet" href="styles.css"> |
| 53 | + </head> |
| 54 | + <body> |
| 55 | + <header> |
| 56 | + <div>My awesome website</div> |
| 57 | + </header> |
| 58 | + |
| 59 | + <main> |
| 60 | + <h1>Common HTML elements</h1> |
| 61 | + ... |
| 62 | + </main> |
| 63 | + |
| 64 | + <footer> |
| 65 | + <div> |
| 66 | + Check us out |
| 67 | + <a href="https://github.com/mastrojs/mastro"> |
| 68 | + on GitHub |
| 69 | + </a>. |
| 70 | + </div> |
| 71 | + </footer> |
| 72 | + </body> |
| 73 | +</html> |
| 74 | +``` |
| 75 | + |
| 76 | +Notice how the `h1` is still the same? That's because soon you'll add more pages, and the `h1` should contain the title of the page, not the title of the entire website. |
| 77 | + |
| 78 | +The `div` element is a generic division, and carries no semantic meaning: to screen-readers it's as if the element wouldn't be there. We add it here only, because unfortunately we need an additional element there to style with CSS. As long as we only have a single block of text in the header and footer, we could have used a `p` element as well. |
| 79 | + |
| 80 | +While the `div` is a block element (meaning it introduces a linebreak before and after), the corresponding inline element is the `span`. However, this could be overriden, with the CSS `display: inline;` or `display: block;` respectively. |
| 81 | + |
| 82 | +To style the newly added elements, use something like: |
| 83 | + |
| 84 | +```css title=routes/styles.css del={4-5} ins={6-7} ins={10-27} |
| 85 | +body { |
| 86 | + font-family: Helvetica, Arial, sans-serif; |
| 87 | + font-size: 18px; |
| 88 | + max-width: 30em; |
| 89 | + margin: 0 auto; |
| 90 | + margin: 0; |
| 91 | + --brand-color: aquamarine; |
| 92 | +} |
| 93 | + |
| 94 | +header { |
| 95 | + background-color: var(--brand-color); |
| 96 | + color: green; |
| 97 | + font-weight: bold; |
| 98 | + font-size: 50px; |
| 99 | + padding: 1.5em 1em 1em 1em; |
| 100 | +} |
| 101 | + |
| 102 | +main { |
| 103 | + padding: 1em; |
| 104 | +} |
| 105 | + |
| 106 | +footer { |
| 107 | + background-color: var(--brand-color); |
| 108 | + padding: 2em 1em; |
| 109 | + margin-top: 3em; |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +Note how we declare `--brand-color` – a _CSS custom property_, also known as a _CSS variable_, and set its value to `aquamarine`. In two places, we use the variable with `var(--brand-color)`. |
| 114 | + |
| 115 | +Further, we set the `color` property of the `header` to `green`, which (like `aquamarine` before) is one of the built-in color names. Instead, you could equivalently set this to `rgb(0, 128, 0)` or `#008000`. |
| 116 | + |
| 117 | +While the `margin` creates space around the element, `padding` creates space inside the element's border. The space inside is filled with the `background-color`. |
| 118 | + |
| 119 | + |
| 120 | + |
| 121 | +`padding: 1.5em 1em 1em 1em` sets four different properties in a clockwise fashion: `padding-top` to `1.5em`, then `padding-right`, `padding-bottom`, and `padding-left` to `0`. |
| 122 | + |
| 123 | +Now add the following at the bottom of `routes/styles.css`: |
| 124 | + |
| 125 | +```css |
| 126 | +p { |
| 127 | + line-height: 1.3; |
| 128 | +} |
| 129 | + |
| 130 | +header > div, |
| 131 | +main, |
| 132 | +footer > div { |
| 133 | + max-width: 30rem; |
| 134 | + margin: 0 auto; |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +The part that describes what elements the rule will select, is called the _CSS selector_. In the snippet above, `p` is the first selector. Notice how `p` selects _all_ HTML `p` elements. |
| 139 | + |
| 140 | +`header > div` selects all `div` elements that are direct children of a `header` element. Because we want the same styles to also apply to `main` and the `div` in the `footer`, we use a comma-separated _selector list_ containing these three selectors. The newlines after the commas are not necessary, but perhaps make it more readable. |
| 141 | + |
| 142 | + |
| 143 | +## Exceptions to the rule |
| 144 | + |
| 145 | +You've seen the power of starting with semantic HTML, and then styling these with CSS element selectors. That's how you can keep your design consistent. However, sometimes you want to have an exception. That's what classes are for. |
| 146 | + |
| 147 | +Perhaps you want some, but not all, of your ordered lists to be enumerated with Roman numbers. On line 42 of your HTML file, change your list: |
| 148 | + |
| 149 | +```html title=routes/index.html del={1} ins={2} |
| 150 | + <ol> |
| 151 | + <ol class="roman"> |
| 152 | + <li>list item one</li> |
| 153 | + <li>list item two</li> |
| 154 | + <li>list item three</li> |
| 155 | + </ol> |
| 156 | +``` |
| 157 | + |
| 158 | +And add to your CSS: |
| 159 | + |
| 160 | +```css title=routes/styles.css |
| 161 | +.roman > li { |
| 162 | + list-style-type: upper-roman; |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +The `.roman` selects all elements with the class `roman`. The `> li` selects all `li` (list item) elements that are direct children of that element. |
| 167 | + |
| 168 | +We could have also written `.roman li`, which would select _all_ `li` nested anywhere inside the element with the class `roman`. But that can often have unintended side-effects, especially with elements that contains lots of deeply nested children. Thus usually it's better to stick with the direct child combinator `>`. |
| 169 | + |
| 170 | +:::tip[Want to learn more CSS?] |
| 171 | +For a more thorough introduction, see the [MDN guide on CSS](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics). |
| 172 | + |
| 173 | +A few more links I can highly recommend: |
| 174 | + |
| 175 | +- A series of videos: [Layout Land on YouTube](https://www.youtube.com/playlist?list=PLbSquHt1VCf18lllS0C5quAaOcsuMAC70). |
| 176 | +- Once you are comfortable with the basics, you'll want to read the article [Things I wish I’d known about CSS](https://davesmyth.com/things-i-wish-id-known-about-css). |
| 177 | +- Bookmark the CSS-Tricks guides for [flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) and [grid](https://css-tricks.com/snippets/css/complete-guide-grid/). |
| 178 | +- Learn about _design tokens_ in the video [What are Design Tokens](https://www.youtube.com/watch?v=wtTstdiBuUk). Start by defining your design tokens for fonts and colors as [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties), and use [color-mix](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix) to change the brightness or transparency of colors where needed. |
| 179 | +- There are many methodologies to structure your CSS (like BEM or rscss), and tools to generate CSS (ranging from the relatively simple like SCSS or CSS modules, to the complex like Tailwind). However, for a convincing argument in favour of simply sticking with global CSS, I highly recommend [this article](https://www.smashingmagazine.com/2016/11/css-inheritance-cascade-global-scope-new-old-worst-best-friends/). |
| 180 | + |
| 181 | +And once you're ready to ponder the nature of the medium web: |
| 182 | + |
| 183 | +- [A Dao of Web Design](http://alistapart.com/article/dao) – the classic article. |
| 184 | +- [Resilient Web Design](https://resilientwebdesign.com) – a free web book. |
| 185 | +::: |
| 186 | + |
| 187 | + |
| 188 | +## Save your changes |
| 189 | + |
| 190 | +Feel free to play around with the CSS. Once you're happy with the result (or tired of playing around with the design), click the **Generate** button above the preview. Then don't forget to [save your changes in the _Source Control_ tab](/guides/html/#save-changes-and-publish-to-the-web). |
| 191 | + |
| 192 | + |
| 193 | +## Inspect your website with your browser's developer tools |
| 194 | + |
| 195 | +Often, it can be hard to spot an error in your CSS. Or you're unsure where some space comes from – is it padding from the outer element, or margin from the inner one? To help you figure out things like that, your browser has built-in developer tools. |
| 196 | + |
| 197 | +Open a new tab in Firefox or Chrome (or in Safari, first check the _Show features for web developers_ checkbox in _Preferences_ -> _Advanced_). Then once again go to `https://your-user-name.github.io/your-repository-name/`, where you should see your newest changes reflected. |
| 198 | + |
| 199 | +To open your browser's developer tools, press the following three keys on your keyboard: |
| 200 | + |
| 201 | +- Windows or Linux: `Ctrl-Shift-I` |
| 202 | +- Mac: `Command-Option-I` |
| 203 | + |
| 204 | +A pane should open. If it doesn't, see the MDN article on [how to open your browser's developer tools](https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Tools_and_setup/What_are_browser_developer_tools#how_to_open_the_devtools_in_your_browser). |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | +To inspect an HTML element: |
| 209 | + |
| 210 | +1. Click the smallish button in the top left of the newly opened pane. Once clicked, the button should turn blue to signal that it's active. |
| 211 | +2. Then click on any element on your website, for example the heading. (Note that before clicking, when you hover over an element, it will show you in bright colors exactly how much space it takes, including its margins and paddings.) |
| 212 | + |
| 213 | +If you weren't on that tab already, this will switch to the tab called `Elements` in Chrome, or `Inspector` in Firefox. And it will highligh the selected HTML element in the document tree, and show which CSS styles are being applied to it on the right (or depending on screen size, on the bottom). You can temporarily edit things there to see how they change, but any changes will be lost after a refresh of the page. |
| 214 | + |
| 215 | +Instead of inspect elements on the generated website, you can also already do so in the Mastro preview pane. However there, the whole VS Code editor is loaded, and the preview is only a small part of the page (inside an [iframe](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe)). So you'll have to ignore everything around your part of the HTML, and ignore error messages and warnings that originate from VS Code and its many plugins. I would not recommend starting to learn the developer tools there. But once you get the hang of inspecting HTML and CSS, you can definitely also do it in the Mastro preview. |
0 commit comments