Post

Intermediate CSS

Here to brush up on my HTML and CSS skills! The following are notes related to CSS!

Quick recap:

CSS

  • CSS: Cascading Style Sheets, describes how HTML elements are to be displayed, and saves a lot of work as it can control the layout of multiple web pages at once. External stylesheets are stored in CSS files.

In this post, we will look at some HTML elements such as forms and tables, and look at some things we can do with CSS, such as variables, functions, shadows and grid layouts.

Default Styles

Browsers have default styles, and we can use a CSS reset to remove or change these default styles. Chrome’s default HTML stylesheet.

Since there is no guarantee different browsers style everything the same, many developers start their projects with a “CSS Reset”, such as the Meyer Reset, or Normalize.css.

CSS Units

There are different units to define sizes in CSS, absolute and relative units.

  • Absolute units, e.g. px (pixel), is always the same in any context.
  • Relative units change based on their context:
    • rem (and ``em`) both refer to font size, though used to define other sizes in CSS
    • 1em is the font-size of an element (or the parent). E.g. if an element’s font-size is 16px, then setting the width to 4em would make its width 64px.
    • 1rem is the font-size of the root element (either :root or html). Math is the same, but without keeping track of parent’s font size.
  • Using a relative size like rem to define font sizes across website is reccomended as browsers allows users to change base font-size to increase readability.

Viewport units

  • Units vh and vw relate to the size of the viewport, where 1vh is equal to 1% of the viewport height and 1vw equivalent to 1% of the viewport width. This can be useful for something sized relative to the viewport, e.g. full-screen app-like interfaces.

More Text Styles

Text manipulation: a few useful CSS properties that can be used when working with text. One way is the change the font-family of an element.

  • If font-family property used to change to font like Times New Roman, and fonts not installed on user’s computer, a fallback font will be displayed. If not defined, default HTML font will be used, which is often ugly.
  • Hence, it is common to see a long stack of fonts listed on projects.
  • Popular stack: ‘system font’ stack.
1
2
3
body {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

Online font libraries A easy method to get fonts that are not installed on a user’s computer is to use an online font library like Google Fonts, Font Library or (non-free) Adobe Fonts. To do so, add the <link> tag to put in the HTML file, or use an @import tag dropped at the top of a CSS file.

1
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
  • As there is no guarantee URL of external API will not change, always add a fallback font.
  • One can also use Downloaded Fonts, by importing and defining a custom font using the @font-face rule in the CSS file, and using it normally.

Other Text Styles

  • font-style: used to make a font italic.
  • Note that HTML <em> tag also uses an italic font, but it signifies that the text it wraps is significant and should be emphasised.
  • Good rule of thumb, if text should be styled, use CSS property. If it has some semantic emphasis, use the correct HTML element.
1
2
3
4
5
6
7
8
9
<!-- If italics is required for styling: -->
h1 {
  font-style: italic;
}

<!-- use em element for emphasis -->
<p>I <em>never</em> said he stole your money</p>
<p>I never said <em>he</em> stole your money</p>
<p>I never said he stole <em>your</em> money</p>
  • letter-spacing: changes space between letters, useful for adjusting custome fonts, can also be good for some cases, e.g. headers.
  • line-height: adjusts space between lines in wrapped text. Adding a little can increaase readability.
  • text-transform: changes the case of the given text.
  • text-shadow: adds a shadow around the text, best used sparing.
  • ellipsis: not a single property, but with text-overflow property, can truncate overflowwing text with an ellipsis.

More CSS Properties

  • background: shorthand for 8 different background-related properties.
    • Beyond changing background-colors, can also specify background images, change position and size of background images, and change how background images repeat or tile if they are too small to fill their container. It is also possible to have multiple background layers.
  • borders: The border property is another shorthand, but it is much less complicated than the background shorthand. For borders, basically you just need to define a size, style and color.
    • border-radius: property that is used to create rounded corners on things.
  • box-shadow: adds a shadow effect around an element. This is useful to create a sense of depth on your page and to add subtle separation between elements.
  • overflow: define what happens to an element when its content is too big to fit.
  • opacity.

Advanced Selectors

Aside from basic CSS selectors, there are more advanced that target elements in a more specific and finely grained way, which can be useful when you can’t change your HTML markup.

  • Parent and sibiling selectors
  • Difference between pseudo classes and pseudo elements
  • Useful common pseudo elements and pseudo classes
  • Different ways to select and attibute or its parts.

Child and sibling combinators

Some ways to access different elements without referring to their classes. Here are three new selectors to do just that.

  • > - the child combinator
  • + - the adjacent sibling combinator
  • ~ - the general sibling combinator

Sample Markup:

1
2
3
4
5
6
7
8
9
10
11
<main class="parent">
  <div class="child group1">
    <div class="grand-child group1"></div>
  </div>
  <div class="child group2">
    <div class="grand-child group2"></div>
  </div>
  <div class="child group3">
    <div class="grand-child group3"></div>
  </div>
</main>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* This rule will only select divs with a class of child */
main > div {
  /* Our cool CSS */
}

/* This rule will only select divs with a class of grand-child */
main > div > div {
  /* More cool CSS */
}

/* This rule will only select the div with the class child group2 */
.group1 + div {
  /* Our cool CSS */
}

/* This rule will only select the div with the class child group3 */
.group1 + div + div {
  /* More cool CSS */
}

/* This rule will select all of .group1's siblings - in this case the 2nd and 3rd .child divs */
.group1 ~ div {
  /* Our cool CSS */
}

Pseudo-selectors, pseudo-classes

  • Pseudo-class selectors are prefixed with a single colon and are a different way to target elements that already exist in HTML.
  • Pseudo-elements are prefixed with two colons and are used to target elements that don’t normally exist in the markup.

Pseudo-classes offer us different ways to target elements in our HTML. There are quite a lot of them, and they come in a couple of different flavors. Some are based on their position or structure within the HTML. Others are based on the state of a particular element, or how the user is currently interacting with it.

Dynamic and user action pseudo-classes These types of useful pseudo-classes can make your page feel much more dynamic and interactive.

  • :focus applies to an element that is currently selected by the user either through selecting it with their cursor or using their keyboard.

  • :hover will affect anything under the user’s mouse pointer. It can be used to give extra oomph to buttons and links to highlight that they’re interactable, or to trigger a drop-down menu.

  • :active applies to elements that are currently being clicked, and is especially useful for giving your user feedback that their action had an effect. This is a great one to give your buttons and other interactive elements more ‘tactile’ feedback.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /* This rule will apply to all links */
  a {
    text-decoration: underline;
  }

  /* This will apply to unvisited links */
  a:link {
    color: blue;
  }

  /* And you guessed it, this applies to all links the user has clicked on */
  a:visited {
    color: purple;
  }

Structural pseudo-classes

Structural pseudo-classes are a powerful way to select elements based on their position within the DOM.

:root is a special class that represents the very top level of your document - the one element that has no parents. Generally when working with the web, this is equivalent to the html element, but there are a few subtle differences.

:root is generally the place where you will place your ‘global’ CSS rules that you want available everywhere - such as your custom properties and CSS variables, or rules such as box-sizing: border-box;.

:first-child and :last-child will match elements that are the first or last sibling.

Similarly, :empty will match elements that have no children at all, and :only-child will match elements that don’t have any siblings.

For a more dynamic approach we can use :nth-child. This is a flexible pseudo-class with a few different uses.

1
2
3
4
5
6
7
  .myList:nth-child(5) {/* Selects the 5th element with class myList */}

  .myList:nth-child(3n) { /* Selects every 3rd element with class myList */}

  .myList:nth-child(3n + 3) { /* Selects every 3rd element with class myList, beginning with the 3rd */}

  .myList:nth-child(even) {/* Selects every even element with class myList */}

Pseudo-elements

While pseudo-classes give us an alternative way to interact with our HTML elements based on their state or structure, pseudo-elements are more abstract. They allow us to affect parts of our HTML that aren’t elements at all.

::marker allows you to customize the styling of your <li> elements’ bullets or numbers.

::first-letter and ::first-line allow you to (you guessed it!) give special styling to the first letter or line of some text.

::selection allows you to change the highlighting when a user selects text on the page.

::before and ::after allow us to add extra elements onto the page with CSS, instead of HTML. Using it to decorate text in various ways is one common use case.

1
2
3
4
5
6
7
8
9
10
11
12
13
<style>
  .emojify::before {
    content: '😎 🥸 🤓';
}

  .emojify::after {
    content: '🤓 🥸 😎';
}
</style>

<body>
  <div> Let's <span class="emojify">emojify</span>this span!</div>
</body>

Attribute Selectors

Recall that an attribute is simply anything in the opening tag of an HTML element - such as src=’picture.jpg’ or href=”www.theodinproject.com”. Since we write our own values for attributes, we need a slightly more flexible system to be able to target specific values.

  • [attribute] - This general selector will select anything where the given attribute exists. Its value doesn’t matter.
  • selector[attribute] - Optionally we can combine our attribute selectors with other types of selectors, such as class or element selectors.
  • [attribute="value"] - To get really specific, we can use = to match a specific attribute with a specific value.
1
2
3
4
5
6
7
8
9
10
11
  [src] {
    /* This will target any element that has a src attribute. */
  }

  img[src] {
    /* This will only target img elements that have a src attribute. */
  }

  img[src="puppy.jpg"] {
    /* This will target img elements with a src attribute that is exactly "puppy.jpg" */
  }

Exercises:

CSS Positioning

Moving elements around the screen using margin, padding and flexbox rely on CSS’s default “positioning-mode”, which is intuitive. However, there are other methods that can be useful.

  • Absolute positioning
  • Fixed positioning, Sticky positioning.
  • Difference between each and how to combine them.

Static and relative positioning

The default positioning mode position: static.

  • Static is the default position of every element, and properties top, right, bottom, and left do not affect the position of the element.
  • Relative is similar to static, but properties top, right...(etc.) displace the element relative to its normal position in the flow of the document.

Absolute positioning

position: absolute allows positioning something at an exact point on the screen without disturbing the other elements around it.

  • Using absolute positioning on an element will remove that element from the normal document flow while being positioned relative to an ancestor element.
  • Elements that are removed from the normal flow of the document don’t affect other elements and are also not affected by other elements.

Using absolute positioning positioning of elements anywhere on the screen using top, right, bottom, and left properties. Useful to position something at an exact point on the screen, without disturbing other elements. (e.g. modals, image with a caption on it, icons on top of other elements).

Fixed positioning

Fixed elements are also removed from the normal flow of the document and are positioned relative to the viewport. You basically use top, right, bottom, and left properties to position it, and it will stay there as the user scrolls. This is especially useful for things like navigation bars and floating chat buttons.

Sticky positioning

Sticky elements will act like normal elements until you scroll past them, then they start behaving like fixed elements.

  • They are also not taken out of the normal flow of the document.
  • Useful for things like section-headings. (E.g. being able to still see what category you’re looking at)

Summary:

  1. static: Default one.
  2. relative : Same as static. But lets you add top, right, bottom, left. Makes it move relative to it’s normal position
  3. absolute: Removes from the flow and positions absolute wrt to the parent. Parent has to be relative or absolute for top, right, bottom, left to work. Else it considers the main html element as the parent .
  4. fixed : Fixed to a place. Doesn’t give two shits about the parent. Always considers html element as the parent. Stays there when scrolled.
  5. sticky : Relative ( when normal) + fixed ( when scrolled). The values for top, right, bottom, left become active when scrolled

See here for a quick demo.

CSS Functions

CSS has functions as well, that accept arguments between parentheses. CSS has list of premade functions that help solve common styling problems.

1
2
color: rgb(0, 42, 255);
background: linear-gradient(90deg, blue, red);

Several functions:

  • calc(): Used for mixing units, ability to nest.
  • min()
  • max()
  • clamp(): takes 3 values, smallest value, ideal value, largest value.
1
2
3
4
5
6
:root {
--header: 3rem;
--footer: 40px;
--main: calc(100vh - calc(var(--header) + var(--footer)));
}

For more CSS functions, see here.

Custom Properties

Custom properties (aka CSS variables) as tools when writing CSS files.

  • Allow us to reference a CSS value throughout a file.
  • Only need to update a single instance: the custom property itself. (e.g. to keep colors consistent throughout a project)
  • Can redefine custom properties under different contexts, e.g. dark and light themes

Syntax for declaring and accessing a custom property:

1
2
3
4
5
6
7
8
9
.error-modal {
  --color-error-text: red;
  --modal-border: 1px solid black;
  --modal-font-size: calc(2rem + 5vw);

  color: var(--color-error-text);
  border: var(--modal-border);
  font-size: var(--modal-font-size);
}
  • Declare our custom property with a double hyphen followed by a case-sensitive, hyphen-separated property name
  • To access a custom property, use the var() function as the value of a CSS property, and place custom property inside of the parenthesis (including the double hyphen at the beginning).
  • The var() function actually accepts two parameters. The second parameter is an optional fallback value.

Scope: Scope of a custom property is determined by the selector. This scope includes the selector the custom property was declared for as well as any descendants of that selector.

Creating themes with custom properties

Beyond allowing us to access custom properties more globally, the :root selector gives us one way to add themes to our pages:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!-- HTML --->
<div class="container">
  <p>You're now viewing this example with the <span class='theme-name'>dark</span> theme!</p>
  <button class="theme-toggle">Toggle Theme</button>
</div>

<!-- CSS --->
:root.dark {
  --border-btn: 1px solid rgb(220, 220, 220);
  --color-base-bg: rgb(18, 18, 18);
  --color-base-text: rgb(240, 240, 240);
  --color-btn-bg: rgb(36, 36, 36);
}

:root.light {
  --border-btn: 1px solid rgb(36, 36, 36);
  --color-base-bg: rgb(240, 240, 240);
  --color-base-text: rgb(18, 18, 18);
  --color-btn-bg: rgb(220, 220, 220);
}

body,
.theme-toggle {
  color: var(--color-base-text);
}

body {
  background-color: var(--color-base-bg);
  padding: 10px;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

p {
  font-size: 1.5rem;
}

.theme-toggle {
  background-color: var(--color-btn-bg);
  border: var(--border-btn);
  font-size: 1.125rem;
  padding: 10px 20px;
}

.theme-toggle:hover {
  cursor: pointer;
}

.theme-toggle:focus {
  outline: var(--border-btn);
}
function setTheme() {
  const root = document.documentElement;
  const newTheme = root.className === 'dark' ? 'light' : 'dark';
  root.className = newTheme;
  
  document.querySelector('.theme-name').textContent = newTheme;
}

document.querySelector('.theme-toggle').addEventListener('click', setTheme)

Media queries Giving users the ability to toggle a theme themselves is great, but there’s another option for setting a theme that you may have come across on certain sites or applications: using the user’s theme setting from their operating system or user agent (like a browser).

  • This can be accomplished with the prefers-color-scheme media query, which checks whether a user has selected a theme preference on their OS/user agent.

Browser Compatibility

Depending on the browser (Chrome, Edge, Firefox, Safari etc.), different engines are used to display information on the web page. Applications may behave differently in the browser.

When developing web dev projects to have a broader reach, one must make sure that it is tested against browsers most likely used.

W3C (World Wide Web Consortium) is the authority behind developing web standards to maximize accessibility and consistency of the web experience. W3C is also the authority to develop new features in the CSS. This is a closely collaborative approach with the Web as a community as well as the companies developing the web browsers.

Using new features

There is a risk of rushing when implementing new features. “Can I Use” is a great resource to help you validate if new features are supported by the browsers. It provides statistics on which browsers and platforms are supporting new technologies, and even which versions of the browsers support specific features.

Mobile browsers

As you are developing your applications, you must also consider whether your application should be fully mobile compatible. There are a couple of specifics about mobile browsers that you need to keep in mind.

Frameworks and Preprocessors

CSS frameworks and preprocessors. Commonly found in workplaces, helpful to know what these tools are and where to look for them. . All of these frameworks and preprocessors are based around vanilla CSS.

Frameworks

Different frameworks have different goals.

  • Frameworks like Bootstrap do a lot of the heavy lifting of packaging up commonly used CSS code for you, even icons and interactions (like menu dropdowns). Designed to abstract away the process of coding intuitive, reusable, and responsive elements.
  • Things like Tailwind aim to simply change how we apply CSS through a different syntax, by supplying pre-named classes that typically only apply a single line of CSS each.
  • A CSS framework is ultimately just a bundle of CSS that you can use and access, using the classes defined by the framework.

E.g. many frameworks provide a class called .btn that will add all the needed styles to your buttons, without you having to write any CSS. In general, to use a framework, you need to understand how it expects you to structure your website and which classes it uses to apply its specific set of styles.

  • You should be aware that there are quite a few frameworks available. Two other frameworks you may come across are Bulma and Foundation.

Disadvantages:

  • Frameworks good for rapidly producing sites with interfaces that are easy to interact with.
  • However, similar use of frameworks produce similar sites. Additionally, new developers jump into learning frameworks too early, and do not have enough CSS practice.
  • Process of overriding framework’s styling or debugging style issues becomes difficult without CSS fundamentals.

Preprocessors

Preprocessors (aka precompilers) are languages that help you write CSS more easily.

  • Reduce code repetition and provide all sorts of time-saving and code-saving features.
  • E.g. allows write loops and conditionals, and join multiple stylesheets.

CSS preprocessors are essentially extensions to vanilla CSS that provide some extra functionality. When you run the processor, it takes your code and turns it into vanilla CSS that you can import into your project.

Preprocessors do have some unique and helpful tools, but many of their most helpful features have been implemented in vanilla CSS, so it might not be worth the overhead of learning one unless you think you really need these features. For example, you have already learned about custom properties which used to be something only possible with preprocessors. CSS nesting also used to be a common advantage of some preprocessors but has now made its way into vanilla CSS and has recently started getting more browser support.

  • Some of the standard preprocessors in use are SASS, LESS and Stylus.
This post is licensed under CC BY 4.0 by the author.