Styling Content with CSS

So Many Colors, So Many Style Possibilities

CSS is an acronym for Cascading Style Sheets, a style sheet language that controls the presentation of <html> elements when displayed in the browser. This article is a follow-up to semantic markup and explores fundamental usage of CSS best practices to follow when styling content for a web applications. Topics covered include:

  1. Create and Load a Stylesheet
  2. CSS Snytax Keynotes
    • Selector Types & Length Units
  3. Making Declarations
    • Container Layout, Placement & Sizing
    • Backgrounds, Borders, Colors & Typography
  4. Style Sheet Format and Structure
  5. Debugging and Optimizing CSS

 Create and Load a Stylesheet

Implementing CSS begins by creating a file that ends with the .css file extension and placing it into a folder titled 'css' in the project folder.Next, load the stylesheet into the <head> of the <html> document using the <link> tag, its required attributes and their respective keywords to notify the browser that this is a cascading style sheet: href="URL", rel="stylesheet" and type="text/css".

Linking a CSS File with an HTML Document
CSS <Link> Strategy

Now, lets focus on writing CSS!

 Understanding CSS Syntax

In life, there are rules: when you follow the rules, you are rewarded and when you break a rule, well, all hell breaks loose. Same analogy applies to CSS: there are rules for writing CSS to instruct a document how to display content. CSS is created by employing a rule-set, which is a block of code that consists of a selector and a declaration.

selector { property: keyword/value; }

selectors reference <html> elements targeted for styling. Its declaration is made of a property and a value: the property identifies which element feature to modify while the value quantifies to what extent the property is modified.

This section is designed to explain syntax rules by dissecting a variety of rule-sets in common situations designers will encounter. It begins with an explanation of how <html> elements are used as selectors and the means by which they can be manipulated. Length units are then explored in an effort to understand how elements move or are shaped, creating the perfect segway into the next section highlighting use case declarations.

 Selector Types

All <html> elements can be used as a selector, but other things can be used as a selector as well. This first group of selectors are targeted most frequently.

 Simple Selectors

The universal selector is the most powerful selector of all as it is used to render styles to all elements in a document. The element selector renders styles to that type of element. The .class selector renders styles on elements that possess a specific class attribute. The #id selector should not be used in CSS because it is a unique identifier that should be used exclusively as a 'hook' for <html> and JavaScript implementations.

 Combinators

The power of selectors can be amplified by using a combinator: syntax that unifies the relationship between any of the selectors used above that targets and applies styles to <html> elements based on a specific criteria. The descendant selector targets elements that descend from a specific element. The child selector targets children of a specific element. The adjacent sibling selector targets immmediate siblings of a specific element. The general sibling selector targets all siblings of a specific element. Selectors can also be grouped allowing application of a consistent style theme to grouped elements.

 Attribute Selector

There are also attribute selectors that can be utilized to target particular features within an <html> element, such as those used with the <form> element.

 :Pseudo-Class

There are also selectors that have selectors! :pseudo-class selectors are keywords added to selectors to invoke a special 'state' during a particular instance. The examples below dictates how <a> elements can be modified based on a particular instance. The keywords below are grouped categorically to highlight usage cases. This first group of selectors are useful for <form> and <link> elements:

A number of pseudo-class selectors are based on an elements position and will often select an element based on a particular instance.

 :Pseudo-Elements

::pseudo-element selectors, on the other hand, are used to style a specific part of a selected element. The difference between the two is in the number of colons. Ther following selectors add depth to elements that possess text.

The ::first-letter and ::first-line pseudo-elements apply styles to the first letter or first line of text, respectively, but they can only be applied to block-level elements.

The ::before and ::after pseudo-elements are used to add content before or after an element. The key to these selectors is that they require the content: ""; property in order to work whereas the content is an icon or background image. Use ::cue to style media captions and ::placeholder to highlight <input> text instructions.

 Length Units

Properties accept a keyword or length unit as a value to qualify or quantify an expected aesthetic quality. Keywords have a precise meaning for how an element should behave. Often, a unit -a numeric value, is required, and in such an instance, such value will be one of three data types: dimension, integer/number or a percentage. Learning keywords for the several hundred properties will take some time, but quickly grasping length units is imperative for outputting the simplest of style declarations.

 Absolute vs. Relative Units

Length units are either absolute or relative in nature: absolute units are fixed and appear as the declared size regardless of screen size while relative units represents a length with the ability to scale relative to other elements on the page. With respect to responsive web design, it is obvious that relative units are a preferred choice. The pixel (px) unit is an anomoly in that it has an immutable absolute value, yet, is relative to screen resolution. Another common value is the percentage (%) relative unit: use of this is risky in that that element becomes relative to its parent. One suggestion for avoiding any risk is to add the rule-set below to the top of the style sheet then never use again, laying the foundation for a responsive design:

html { font-size: 100%; }

Relative units that build responsiveness include em, rem, vh, vw, vmin, vmax and calc(). Both em and rem units focus on styling font-size with the exception being that the former is relative to its parent while the latter is relative to the root element. Viewport units are relative measurements that provide percentage-based calculations for responsive design, making these the idea choice when working with images and layouts.

The viewport height (vh) and viewport width (vw) units reflect an equal percentage of their respective viewport dimensions. Use the vh units on the height property to create full-screen sections. The vmin and vmax unit represents the percentage of viewport height or width, for whichever is smaller or larger. When vmin is used on an elements height and width, all aspects of that element will be viewable within the viewport. Viewport units are particularly helpful for designing responsive layouts! The calc() function provides a calculation that formulates responsiveness on the element of which it is applied, allowing font-size to scale depending on the device screen size. A vw can be added to this function to implement fluid typography.

 Dimensional and Time Units

Not all values are created equal so when designing animations out from the abyss of time and space, it is helpful to be aware of dimensional and time measurement units. Time units are easy to remember: seconds (s) and milliseconds (ms). Using dimensions, not so much. The rotate() function is used to calculate a transformation on a specified element. This function works in conjunction with the degree (deg) and turns (turn) units, which are used to rotate or turn an object with the only distinction being that one turn reflects a full 360 degree whereas one degree equals just that.

Although outside of the scope, there are other math functions that are used when designing animations.

That was a good bit on numeric values all of which will be utilized throughout a typical style sheet. With a solid foundation of how values work, designers can focus on developing their property memory bank, and the best properties to jumpstart this initiative focus on layout.

 Making Declarations

There are a lot of properties available for styling a document: no project regardless of size will utilize all of them. Lets look at some scenarios a designer can expect to encounter when making declarations for an aesthetically pleasing, yet, fully responsive website.

 Container Layout

When structuring a layout, it is a best practice to invoke {box-sizing: border-box;} at the top of a style sheet. This declaration eliminates spacing concerns by taking into account an elements padding and border along with its width and height. Ths sets a foundation for layout and positional properties used on elements thereafter. From there, the first property designers reach for is that of display, which determines how an element is displayed. The main goal of this property emphasizes element alignment.

{display: inline / block / none;}

These keywords are old hat in that they were used from the start to emphasize horizontal and vertical layout, but their value has waned over time. The keyword inline is the default value for elements that wrap text along the horizontal axis, such as <span>. The keyword block is the default value for elements that act as containers: the <div> and <ul> elements are abvious examples, but the <p> and <h1> elements are also considered a block. Use the none keyword to hide elements.

It can be a cumbersome task to use the aforementioned keywords to style a large website, but designers did it this way for eons basing elements as either a row or column. Nowadays, layout techniques are implemented using the keywords flex and grid, and although nearly the same, both are used in distinct ways. flex is one-dimensional and is best used to arrange individual items in a single row or column whereas grid is two-dimensional and is best used to establish containers by arranging items in multiple rows or columns. Thus, what distinguishes these keywords is that grid defines a parent element while flexbox defines child elements. With that in mind, lets first focus on structuring a container.

 The Grid

The {display: grid; } declaration sets up a layout pattern that allows elements to be placed in fixed or flexible positions along the cross-axis of perpendicular lines. There are sub-properties that designers should familiarize themselves with to manipulate the layout according to specifications.

The sub-props {g-t-c: val;} and {g-t-r: val;} are used to explicitly specify column and row track sizes. The {g-t-a: key;} sub-prop is an elaborate method to accomplish this same feat, yet, is outside of the project scope. To implicitly layout columns and rows, invoke the auto-placement algorithm using {g-a-f: key;}: flow direction is determined using the keywords column or row. Additionally, the keyword dense can be added to the declaration in order to remove dead space between items of varying size, forcing columns or rows to flow in a natural order. In any case, use {grid-gap: value;} to add gutters between both columns and rows.

The length units previously learned can be applied to sub-properties here for customization, but the true power of grid is the use of a unique set of keywords, math functions and fractional units.

The essential grid keywords designers need to know: auto-fill, auto-fit, min-content and max-content. Both auto-fill and auto-fit are used to automatically size columns (cannot be used to size rows). Both add as many columns to the row as possible, but the difference is that the former fills the row with as many items as possible, while the latter will fit items before collapsing onto the next row. min-content and max-content represent the minimum and maximum width allotted for content in a grid item.

A fractional unit #fr specifies that an element take up a fraction of space where an allotment is available: 1fr uses one fraction of space; 2fr uses two, so on and so forth. Fractional units consistently size elements and work well with math functions.

The minmax(x, y) function simplifies calculating a formula for distributing space among elements by establishing a range between a minimum (x) and maximum (y) value to explicitly set columns or rows. It accepts any of the aforementioned keywords and measurement units as a value. In the example below the auto keyword is used to set the the value at minimum or maximum.

The repeat(x, y) function is an awesome features that allows the declaration to be applied repeatedly to an element, and can be combined with all of the aforementioned keywords and values.

Designer magic takes place once these powers are combined!

 Grid Examples

There are also properties used with grid that targets layout structure for grid-items. The justify-items and align-items properties provide horizontal and vertical alignment of grid items.

The justify-content and align-content properties to align grid-items horizontally or vertically within its parent container.

 Flexbox

The flex keyword is used to create a container that allows its direct children to be flexible. The children are called items and their layout structure is defined by a set of sub-properties that work only when the display has been set to work. The flex-direction sub-prop assigns if items will flow in a column or row. Because all items will try to fit onto the same line, the flex-wrap prop can be used to wrap items to the next line. Apply margin and padding to create gutters.

The justify-content sub-prop manages item alignment along the main horizontal axis.

The align-items sub-prop manages item alignment along the cross vertical axis.

 Sizing and Placement

There are a variety of elements that allow designers to make modifications that effect size and placement.

 Sizing and Shaping Elements

The height property is used to specify content height and width of boxes. The min/max-height properties can be added to an element that has a height of 100% to create a minimum and maximum element container height.

The width property is used to specify content width of boxes. min/max-width properties can be applied in the same fashion as that of the height property. The fit-content and min-content keywords can be used to center child elements.

The Margin property specifies the outside borders of an element. The Padding property specifies the inside borders of an element. Both props accept a single value as a shorthand for top, right, bottom or left sides.

The clip-path property can be used to create shapes that display specific areas of an areas content. It is mostly used with images, but can be applied to text elements as well.

clip-path: polygon();

All shapes are formed using different values and points of reference. Use this clip-path maker to create common shapes and to tinker with.

All values represent basic-shape values to effectively create shapes. The inset() marks the top, left, bottom and right points to form lines that can shape rectangles and squares, or create a roundness on a shape. The polygon() value can be modified to create extravagant shapes.

 Positional Placement

There are several ways to position elements: techniques explained herein highlight but a few.

The float property is used to wrap text around images. This is a simple method of positioning an element, but designers should consider that a floated elements position is dependent on the position(s) of element(s) that surround it. One way to contain a floated element is to use the overflow property to control what happens to content that breaks outside of its boundaries: this declaration is applied to the parent element of the floated element..

The position property offers greater control over how and where an element is positioned as it can be used to re-position an element from its initial position. It accepts one of five keywords to provide instructions on how and where an element is placed. By default, an element will flow in a natural order amongst fellows.

The relative keyword specifies that an element is positioned relative to other elements while the absolute key is positioned relative to its nearest ancestor. For example, to position an element #px below its parent, apply {position: relative;} with {top: #px;}. Position an element flush to the bottom using {position: absolute;} with {bottom: 0px;} and {right: 0px;}.

The fixed key positions elements at a specified point within the viewport: a fixed element will never shift positions. The sticky key will position an element relative to other elements until a specified viewport position is met. These keys work in conjunction with offset properties to set the precise placement of an element.

The z-index property controls the vertical stacking order of elements that overlap. This property only impacts non-static positioned elements.

The object-fit prop approximates how embedded media elements react to the height or width of its parent. It works well with the object-position prop to position a media element along the X/Y axis within its parent.

Use a media query to optimize a website by making it responsive at varying breakpoints.

 Size and Position Examples

Fixed Footer

 Media

When dealing with images, it is best to use either.jpg or .png formats. All images have an absolute height and width defined in pixels, thus, modifying these values will distort the image. Try using the .webp format. Below are useful declarations:

 Colors

The color property specifies the color of a text element and can be applied to text decorations and shadows. A color can be assigned using a color name or an rgb value. There is a standard list of color names that can be used and the easiest way to write and RGB value is to use hexadecimal string notation.

RGB values can be invoked using a function that can be especially useful for professional artists. The rgb() function accepts four parameter values for red, green, blue and opaqueness (optional). The hsl() function is unique it that it controls the color hue, saturation and lightness. These functions are worth exploring further.

There are lot of cool ways to style elements using colors, but choosing the right color can be a burdensome process for multiple reasons. Designers who are not natural artists should learn concepts of color theory, seek out palette tools that assist with creating a compatible color schemes and be weary of accessibility concerns that could impact the ability of color-blind users to effectively navigate a web app.

 Backgrounds and Borders

The background property is used to layer an image underneath content. As a shorthand, it accepts sub-props that include image, position, size, repeat, attachment, origin, clip and color.

border is a property that applies a border around and element. As a shorthand, it accepts keywords and values for its width, style and color.

The border-radius property applies rounded corners on elements, accepting 1, 2 or 3 values.

The box-sizing property can also be used to cast a shadow on an element. The values represent the horizontal/vertical offset, blur radius, spread radius and color assigned to the offset. All but the spread radius are required.

 Typography

Typography encapsulates the visual component of the written word and is a critical branding variable. Text should be presented in a way that is useful, legible and provokes an emotional connection. While typeface is the design of a collection of characters, Fonts embody a particular style of a typeface.

There are three genre types that developers should be familiar with: serif, sans-serif and scripts. Serif font types are fonts that have a diagonal stress at the end/tip of a letter and are typically calligraphic. Sans-Serif font types are fonts that do not have serif endings and these are ideal fonts to use throughout a project. Script font types are either formal or casual. Aside from this, web browsers use different system fonts and this could lead to issues: workaround such nuances by installing a Font-Stack that instructs browsers how to display font.

This process involves choosing a font-stack that has a range of weights, italic styles, numerical figures and language support. After collecting a half-dozen or so font types, evaluate how those fonts will display using visual type scales. Preferred fonts include Bodoni, Bookman, Helvetica, Palitino, Rockwell and Tahoma. Some web-safe fonts include Arial, Garamond, Tahoma, "Lucida Sans", Georgia, "Palatino Linotype" and Verdana.

These tools will be especially useful to visualize typographic hierarchy which is a practice of maintaining spacing and alignment in a way that helps users understand contextual importance. Using small-caps for headline titles, subdued colors for sub-titles, horizontal rules to emphasize text and the em relative length unit for responsiveness are means by which developers can implement a uniform type scheme.

Use the font-family property to define the font that should be applied to text. Font names are separated by a comma";" names that have two or more words should be enclosed in quotation marks. Including a genre type as a fallback is a requirement.

font is an all-purpose property that is used to set the style of text and can be used as shorthand to amalgamate font-style, font-variant, font-weight, font-size, line-height and font-family (when used, these properties must be included in this order; line-height is optional).

The -style is used to italicize text, but is commonly only used within the shorthand.

The -variant makes all text uppercase.

The -weight sets font thickness or width, but its font-family will determine how the weight is applied, if applied at all. Values for this property use an incremental numerical scale from a lot point of 100 to its peak of 900 (increments of 100).

The -size specifies the size of the font using numerical values (ie em, rem + px). The px value is an industry standard static value as it is used for pixel accuracy. The em unit is a responsive type. Calculate the em equivalent for any px value by dividing the desired element px value by its parent element font-size in pixels. The rem value is an alternative to the em unit in that it does not compound as it is relative to the root html element. Its counterpart, the line-height, sets the space above and below inline elements and is useful for evenly spacing lines.

With type, horizontal and vertical spacing are controlled through character per line restrictions and metric tracking. Kerning ratios are imperative here: creating an equal amount of space between a specific character pair (ie AW) adds aesthetic value. Here are a few tools that help visualize the baseline, align-text using the golden section and counting characters, letters and words. It is also important to consider how text contrast with its background color as body text should have a color contrast-ratio of 4.5:1. Learn more about the anatomy of typography.

Although the most convenient method of adding a font to a website would be via a <link> CDN in the <html> markup, it is important to be mindful of measurement units to create responsive typography. Any relative length unit can be used: employ em and pm for the greatest control as they are dependent on parent elements and viewport dimensions. For this reason, it is a good practice to set the html {font-size: 100%;} to ensure the base font-size is set in the browser and to use relative units on all other elements. Other important notes include: use the rem unit on nested elements, avoid using vh/vw units on font-size and use the calc() function to perform math calculations.

The letter-spacing and word-spacing properties manages the amount of space between letters and words, respectively.

The text-decoration property sets a line style on text and can be written in shorthand form to define the line, its style and color (in that order). The text-decoration-style prop will accept values of solid, double, dotted, dashed and wavy.

The text-transform property sets the text case and capitalization.

The writing-mode property sets the vertical and horizontal alignment of text. It is useful when working with Asian languages: when doing so, be sure to implement the word-break property to ensure text words are not broken.

 List-style

list-style is a shorthand property that defines a type, position and image. The list-style-type prop sets what type of bullet to use. The list-style-position prop sets the bullet inside or outside of the margin. The list-style-image prop uses a url to set the bullet as an image.

 Animating Things

Certain properties applied to HTML elements can be animated via transition and transforms properties. Best practices encourage smooth, fluid experiences delivered at 60 frames per second (fps). Animating properties that affect browser layout, such as borders, will lower the FPS and impair the overall performance of the website.

Transitions (transitions-)modify property values over a specified amount of time. Transitioning an element is a relatively simple process: use -property to target the property to transition then set the duration of the transition with the -duration property. Optionally, use -delay and -timing-function to create multiple transitions by setting delays or to the control the transitions overall speed. Timing is the most important when creating animations in order to get a desired effect. The cubic-bezier function is useful to customize transition time intervals for the overall animation of an element. Use an easing functions tool to make this process less stressful. For reasons related to accessibility, it is important to keep transitions between 0.2s and 2s.

Transition properties can be combined to create a shorthand, saving lines of code while improving performance bit by bit.

Transforms modify an elements position and shape using special value functions that rotate, scale, skew and move elements in 2D or 3D space. Dynamic animations can be made using these values individually or in combination with each other.

The rotate() function rotates an element 0 to 360 degrees and accepts angle unit arguments of #deg or #turn. The numerical value assigned to the argument represents a percentage of or a complete rotation, respectively. Maintain a rotating variance between 180 degrees.

The skew() function slants an element horizontally or vertically. The scale() function increases or decreases the size of elements: use two values to scale an element evenly along both axis.

The translate() functions move elements side-to-side or up-and-down along its axis without affecting the position of other elements.

Tidbits: use {animation-play-state: paused;} on hover to pause an animation and use font-variation properties to animate typography with variable fonts. Tinker with these animation examples.

@keyframes is used to define precise styles and intervals to create an animation. It requires a name to connect it with a selector. These are how the best fades are made!

 Style Sheet Format

Writing CSS requires a plan: no plan will result in spaghetti code. There are ways to avoid code purgatory and it all begins with using comments to document points-of-emphasis for each rule-set. This practice makes reading code easier and is especially important when collaborating on a team project. The example below is a single-line comment where the '...' references the comment.

/* ... */

Leaving comments is only one method of writing legible code: double-space indention, lowercase text, meaningful class names, avoiding unnecessary type selectors (ie nesting to deep) and using shorthand properties will go a long way in formatting code so that anyone can read it. Don't be afraid to use lines of space, commented or not, to separate significant chunks of code.

As a dev, it is imperative to comprehend the cascade, inheritance and specificity when structuring a style sheet as these factors hold the key to how styles are applied or if they are applied at all. At the core of CSS is its rule-defining algorithm that defines the order by which CSS rules cascade.

Because style sheets come from different origins, they tend to overlap in scope. For example, browsers use a user-agent style sheet that provides a default style to all documents while devs create authored style sheets. The algorithm defines the interaction between these files by prioritizing their order. Whereas user-agent style sheets are applied by default, an authored style sheet will follow. In the event that multiple declarations of equal value are made in both files, the rule-sheet of the latter style sheet will be prioritized. This is specificity.

The same is true of such an instance taking place within the same style sheet. The example below dictates that the color of the .class will render 'black' because of the source order determination (ie specificity) on which declaration to utilize.

Specificity Exemplified
Specificity Exemplified

Selectors have an applicable specificity rank-order as well where rule-sets are prioritized based on their importance. Selector rank-order (highest-to-lowest) is as follow: #id, .class, [attribute = "val"], :pseudo-class, <element> then ::pseudo-element.

Selector combinators, the negation :pseudo-class [ :not() ] and the universal selector do not impair specificity. The !important exemption [ ! ] and inline-style can be used to override any declaration. However, the exception should be used sparingly, if at all, and it is considered bad practice to write inline-styles.

CSS styles are also controlled via inheritance: the concept that some property values applied to an element will be inherited by its children, but some will not. An example of this is a <p> tag nested in a <div>: setting the color property for the <div> will cause the <p> to be the same color. Setting the color property for the <p> will override the styles applied to the <div>. Always consult a CSS property reference list to ascertain which properties are natively inherited.

In a nutshell: write styles that are broadly applied and have low specificity at the start of a style sheet so that they can be overridden (if necessary) by styles of a higher specificity written beneath them. Thus, include box-sizing, font, preprocessors, and variable definitions at the top of the style sheet followed by default style settings and ending with class-based selectors, components, defined patterns and utilities.

Lastly, employing a naming convention is a beneficial technique that establishes a clear relationship among CSS selectors. The block-element-modifier (BEM) namespace is a method that encapsulates a .class as a block of code bound to an element that can be modified with precision.

.block__element--modifier

Pre-selectors can be used to indicate the purpose of a rule-set. Very useful for distinguishing blocks of code.

.c-block { ... } = an HTML component
.js-block { ... } = For JavaScript
.u-block { ... } = Q+A Automate Tests

 Debugging CSS

There are times when developers write declarations that are not rendered in the browser, and a simple explanation would target a syntax error as the culprit. When this happens, the browser will simply ignore the rule. If this happens, developers will have to resolve the conflict independently, and this sometimes creates headaches. Luckily, there are plenty of resources available to help debug CSS.

Major internet browsers –Chrome, Firefox, Microsoft Edge and Safari, all offer developer tools to help troubleshoot CSS issues. These toolkits employ an element inspector, a styles panel and a mode for responsive debugging that allows developers to understand where styling conflicts exist. When inspecting styles, it is important to note the declarations that are crossed out or have a warning icon, for example, have been overridden or are invalid. Thus, such elements should be the focus for trying to alleviate any style concerns. Learn more about Chrome, Firefox, Microsoft Edge and Safari dev tools.

A simpler way to parse code for potential errors would be to use a linter, which searches for invalid declarations, specificity, and duplicate or unused selectors in an effort to sanitize code of any unnecessary elements. The W3C group has a quality online validator.

There are additional methods that developers can take to optimize a web site and minifying files is a good first step. Minification is the process of removing unnecessary characters from the file in order to improve the files efficiency by decreasing the size of the file.

Above all else, developers can best serve themselves by refactoring their code. Refactoring is the process of organizing code as most efficiently as possible; enhancing readability affords faster code execution, which is the ultimate goal here. When reorganizing code, it is a good practice to subscribe to a specific style guide with criteria that concentrates on declaration order, formatting rules and use of unit-values that you want to use. Employing a Block Element Modifier (BEM) naming convention would provide a more consistent code structure for code sharing in front-end development. Learn more about BEM.