Code listings from CSS In Depth by Keith J. Grant
At first glance, it may appear that some listings are missing—Because working examples requires both HTML and CSS, I have put most listings in an HTML file, using <style>
tags for the CSS. This means that both an HTML listing and CSS listing are combined in one file in the repository.
For example, in Chapter 1, listing 1.1 is HTML code and listing 1.2 is CSS that is meant to be applied to that HTML. I have included these both in the repository in the file named ch01/listing-1.2.html. Changes are made to this CSS in ch01/listing 1.3; these are included in ch01/listing-1.3.html, along with the corresponding HTML from listing 1.1.
- CSS in Depth
- Terminology
- 1. Cascade, specificity, and inheritance
- 2. Working with relative units
- 3. Mastering the box model
- 4. Making sense of floats
- 5. Flexbox
- Sources
- Declaration
- made up of a property (
color
) and a value (black
)
- made up of a property (
color: black;
- Declaration block
- a group of declarations inside curly braces
- a declaration block is preceded by a selector (
body
)
body {
color: black;
font-family: Helvetica;
}
- Ruleset
- the selector and declaration block
- also called a rule
- at-rules
- language constructs beginning with an "at" symbol
@import
rules or@media
queries
- CSS is about declaring rules
- if this class is added to that element, apply these styles
- if element X is a child of element Y, apply those styles
- Predicting how rules behave requires an understanding of the cascade
- Conflicting declarations
- the cascade considers three things to resolve the difference:
- Stylesheet origin: where the styles come from
- your styles are applied in conjunction with the browser's default styles
- Selector specificity: which selectors take precedence over which
- Source order: order in which styles are declared in the stylesheet
- Stylesheet origin: where the styles come from
- the cascade considers three things to resolve the difference:
- Declaration precedence:
- conflicting declarations
- different origin or importance?
- yes: use declaration with higher-priority origin
- no: is one an inline style (scope)?
- yes: use inline declaration
- no: do selectors have different specificity?
- yes: use declaration with higher specificity
- no: use declaration that comes later in source order
- different origin or importance?
- conflicting declarations
- There are different types, or origins, of stylesheets
- author styles: yours
- user agent styles: browser's default styles
- lower priority
- User agent styles
- examples:
- list has a left padding and a list-style-type of disc to produce the bullets
- links are blue and underlined
- heading and the list have top and bottom margins
- examples:
- Overriding user agent styles
- Important declarations
- a declaration can be marked important by adding
!important
color: red !important;
- treated as a higher-priority origin
- overall order of preference, in decreasing order:
- author important
- author
- user agent
- a declaration can be marked important by adding
- If conflicting declarations can't be resolved based on their origin, the browser next tries to resolve them by looking at their specificity
- 99% of the styles on your website come from the same origin
- The browser evaluates specificity in two parts
- styles applied inline in the HTML
- styles applied using a selector
- Inline styles
- "scoped" declarations, which override any declarations applied from your stylesheet or a
<style>
tag - to override inline declarations, you'll need to add an
!important
to the declaration- shifting it into a higher-priority origin
- if the inline styles are marked important, then nothing can override them
- "scoped" declarations, which override any declarations applied from your stylesheet or a
- Selector specificity
- rules of specificity:
- if a selector has more IDs, it wins (it's more specific)
- if that results in a tie, the selector with the most classes wins
- if that results in a tie, the selector with the most tag names wins
- example with decreasing specificity:
- rules of specificity:
#page-title {
color: red;
}
.page-header .title {
color: green;
}
body header.page-header h1 {
color: orange;
}
html body header h1 {
color: blue;
}
- Notes:
- pseudo-class selectors (for example,
:hover
) and attribute selectors (for example,[type="input"]
) each have the same specificity as a class selector - the universal selector (
*
) and combinators (>
,+
,~
) have no effect on specificity
- pseudo-class selectors (for example,
- A notation for specificity
- ID, class, tag (highest to lowest priority)
- examples:
html body header h1
: 0, 0, 4body header.page-header h1
: 0, 1, 3.page-header .title
: 0, 2, 0#page-title
: 1, 0, 0
- Specificity considerations
- when you give several declarations an
!important
, then the origins match and the regular specificity rules apply - it is generally best to keep specificity low when you can, so when you need to override something, your options are open
- when you give several declarations an
- If the origin and the specificity are the same, then the declaration that appears later in the stylesheet, or appears in a stylesheet included later on the page, takes precedence
- Link styles and source order
- selectors for styling links should go in a certain order because source order affects the cascade
- mnemonic to remember this order: LoVe/HAte - link, visited, hover, active
a:link {
color: blue;
text-decoration: none;
}
a:visited {
color: purple;
}
a:hover {
text-decoration: underline;
}
a:active {
color: red;
}
- Cascaded values
- a declaration that "wins" the cascade is called a cascaded value
- 2 common rules of thumb for working with the cascade:
- Don't use IDs in your selector
- when you need to override the selector, you often don't have another meaningful ID you can use
- you wind up having to copy the original selector and add another class to distinguish it from the one you are trying to override
- when you need to override the selector, you often don't have another meaningful ID you can use
- Don't use
!important
- Don't use IDs in your selector
- An important note about importance
- if you're creating a JavaScript module for distribution (such as an NPM package), don't apply styles inline via JavaScript if it can be avoided
- if you do, you're forcing developers using your package to either accept your styles exactly or use
!important
for every property they want to change
- if you do, you're forcing developers using your package to either accept your styles exactly or use
- instead, include a stylesheet in your package
- if your component needs to make style changes dynamically, it's almost always preferable to use JavaScript to add and remove classes to the elements
- if you're creating a JavaScript module for distribution (such as an NPM package), don't apply styles inline via JavaScript if it can be avoided
- If an element has no cascaded value for a given property, it may inherit one from an ancestor element
- Not all properties are inherited
- properties pertaining to text
color
,font
,font-family
,font-size
,font-weight
,font-variant
,font-style
,line-height
,letter-spacing
,text-align
,text-indent
,text-transform
,white-space
, andword-spacing
- list properties:
list-style
,list-style-type
,list-style-position
, andlist-style-image
- table border properties:
border-collapse
andborder-spacing
- properties pertaining to text
- The inheritance will pass from element to element until it’s overridden by a cascaded value
- 2 special values that you can apply to any property to help manipulate the cascade:
inherit
andinitial
- Inheritance to take place when a cascaded value is preventing it
- See
color
of.footer a
inch01/listing-1.15.html
color: inherit;
- overrides the blue link color from
a:link
- inherits from its parent,
<footer>
(.footer
)
- overrides the blue link color from
- You can also use the
inherit
keyword to force inheritance of a property not normally inherited, such asborder
orpadding
- Undo styles applied to an element
- Every CSS property has an initial, or default, value
- assign the value
initial
to that property effectively resets to its default value
- assign the value
- See
color
of.footer a
inch01/listing-1.16.html
- Note:
- declaring
display: initial
is equivalent todisplay: inline
- it won't evaluate to
display: block
regardless of what type of element you apply it to - initial resets to the initial value for the property, not the element;
inline
is the default value for thedisplay
property
- declaring
- Examples:
font
:font-style
,font-weight
,font-size
,line-height
, andfont-family
font: italic bold 18px/1.2 "Helvetica", "Arial", sans-serif;
background
:background-color
,background-image
,background-size
,background-repeat
,background-position
,background-origin
,background-chip
, andbackground-attachment
border
:border-width
,border-style
, andborder-color
border-width
:- top, right, bottom, and left border width
- Most shorthand properties let you omit certain values and only specify the bits you're concerned with
- doing this still sets the omitted values; they'll be set implicitly to their initial value
- silently override styles you specify elsewhere
- See
font
of.title
inch01/listing-1.17.html
- avoid using
font
except to set general styles on the<body>
element
- avoid using
- Shorthand properties try to be lenient when it comes to the order of the values
- when it's clear to the browser which value specifies the property
- But there are many properties where the values can be more ambiguous
- e.g.,
margin
andpadding
- in these cases, the order of the values is significant
- e.g.,
- Units, such as
em
andrem
, are not absolute, but relative - The value of relative units changes, based on external factors
- e.g., the meaning of
2 em
changes depending on which element (and sometimes even which property) you're using it on
- e.g., the meaning of
- In the web environment, the user can have their browser window set to any number of sizes, and the CSS has to apply to it
- Furthermore, users can resize the page after it's opened, and the CSS needs to adjust to new constraints
- Styles can't be applied when you create your page; the browser must calculate those when the page is rendered onscreen
- This adds a layer of abstraction to CSS
- we can't style an element according to an ideal context; we need to specify rules that'll work in any context where that element could be placed
- Relative units are one of the tools CSS provides to work at this level of abstraction
- Instead of setting a font size at 14 px
- you can set it to scale proportionally to the size of the window
- or, you can set the size of everything on the page relative to the base font size, and then resize the entire page with a single line of code
- In CSS,
1 em
means the font size of the current element- its exact value varies depending on the element you're applying it to
- see
ch02/listing-2.1.html
- Values declared using relative units are evaluated by the browser to an absolute value, called the computed value
- Using
em
s can be convenient when setting properties likepadding
,height
,width
, orborder-radius
- these will scale evenly with the element if it inherits different font sizes, or if the user changes the font settings
- see
ch02/listing-2.3.html
font-size
em
s are derived from the inherited font size- For most browsers, the default font size is 16 px
- The keyword value
medium
calculates to 16 px Em
s for font size together withem
s for other properties- when you use
em
s for both font size and any other properties on the same element- the browser must calculate the font size first, and then it uses that value to calculate the other values
- both properties can have the same declared value, but they'll have different computed values
- see
ch02/listing-2.6.html
- when you use
- The shrinking font problem
- shrinking text occurs when you nest lists several levels deep and apply an
em
-based font size to each level- the selector targets every
<ul>
on the page; so when these lists inherit their font size from other lists, theem
s compound - see:
ch02/listing-2.7.html
- fix, see:
ch02/listing-2.9.html
- the selector targets every
- shrinking text occurs when you nest lists several levels deep and apply an
- The HTML DOM root node is the ancestor of all other elements in the document
- has a special pseudo-class selector (
:root
) - specificity of a class
- has a special pseudo-class selector (
rem
is short for root emrem
s are relative to the root element- see:
[ch02/listing-2.10.html
](ch02/listing-2.10.html)
- Note: accessibility - use relative units for font size
- setting browser default font size does not resize fonts defined using pixels or other absolute units
- because a default font size is vital to some users, particularly those who are vision-impaired, you should always specify font sizes with relative units or percentages
- Use:
rem
s for font sizes- pixels for borders
em
s for most other measures, especially paddings, margins, and border radius
- Let's say you want your default font size to be 14 px
- 14/16 = 0.875em
- set the default font size at
:root
- see:
ch02/listing-2.14.html
- You can use some media queries to change the base font size, depending on the screen size
- an
@media
rule used to specify styles that will be applied only to certain screen sizes or media types (for example, print or screen) - a key component of responsive design
- an
/* Applies to all screens, but is overridden for larger screens */
:root {
font-size: 0.75em;
}
/* Applies only to screens 800 px and wider, overriding the original value */
@media (min-width: 800px) {
:root {
font-size: 0.875em;
}
}
/* Applies only to screens 1,200 px and larger, overriding both values */
@media (min-width: 1200px) {
:root {
font-size: 1em;
}
}
- See:
ch02/listing-2.15.html
- These two media queries near the top of your stylesheet can eliminate the need for dozens of media queries throughout the rest of your CSS
- You can change font size globally by only touching one line of code
- Sometimes you might need a larger version of the same part of your interface on certain parts of the page
.panel {
/* Establishes a predictable font size for the component */
font-size: 1rem;
padding: 1em;
border: 1px solid #999;
border-radius: 0.5em;
}
.panel > h2 {
margin-top: 0;
/* Uses ems to make other fonts relative to the established parent font size */
font-size: 0.8em;
font-weight: bold;
text-transform: uppercase;
}
/* Compound selector targets elements with both panel and large classes */
.panel.large {
font-size: 1.2rem;
}
- Viewport-relative units:
vh
: 1/100th of the viewport heightvw
: 1/100th of the viewport widthvmin
: 1/100th of the smaller dimension, height or width (IE9 supports vm instead of vmin)vmax
: 1/100th of the larger dimension, height or width (not supported in IE or, at the time of writing, Edge)
- Viewport-relative lengths are great for things like making a large hero image fill the screen
- your image can be inside a long container, but setting the image height to
100vh
, makes it exactly the height of the viewport
- your image can be inside a long container, but setting the image height to
- Consider what would happen if you applied
font-size: 2vw
to an element- desktop monitor at 1,200 px, this evaluates to 24 px
- tablet with a screen width of 768 px, it evaluates to about 15 px
- 24 px is a bit too large on a big screen, 7.5 px on an iPhone 6
- use
calc()
function to make the extremes less severe
- use
- Basic arithmetic with two or more values
- Useful for combining values that are measured in different units
- Supports addition (
+
), subtraction (-
), multiplication (*
) and division (/
) - Example:
:root {
font-size: calc(0.5em + 1vw);
}
0.5em
operates as a sort of minimum font size, and the1vw
adds a responsive scalar- base font size that scales from 11.75 px on an iPhone 6 up to 20 px in a 1,200 px browser window
- see:
ch02/listing-2.19.html
- Some properties allow for unitless values
- e.g.,
line-height
,z-index
, andfont-weight
- e.g.,
- The
line-height
property is unusual in that it accepts both units and unitless values- you should typically use unitless numbers because they're inherited differently
- when an element has a value defined using a length (
px
,em
,rem
, and so forth), its computed value is inherited by child elements - when you use a unitless number, that declared value is inherited, meaning its computed value is recalculated for each inheriting child element
- See:
- unitless line height:
ch02/listing-2.21.html
- em line height:
ch02/listing-2.22.html
- unitless line height:
- You can declare a variable and assign it a value; then you can reference this value throughout your stylesheet
- particularly useful for recurring values like colors
- must begin with two hyphens (
--
) - must be declared inside a declaration block
- a function called
var()
allows the use of variables- accepts a second parameter, which specifies a fallback value
- See:
ch02/listing-2.26.html
- Note: If a
var()
function evaluates to an invalid value (e.g.,padding: var(--brand-color)
), the property will be set to its initial value
- You can define the same variable inside multiple selectors, and the variable will have a different value for various parts of the page
- due to cascade and inheritance
- See:
ch02/listing-2.29.html
- Custom properties can also be accessed and manipulated live in the browser using JavaScript
- See:
ch02/listing-2.31.html
- With this technique, you can use JavaScript to re-theme your site, live in the browser
- you could also highlight certain parts of the page or make any number of other on-the-fly changes
- Basic page content:
ch03/listing-3.2.html
- Put two columns in place using a float-based layout
.main {
float: left;
width: 70%;
...;
}
.sidebar {
float: left;
width: 30%;
padding: 1.5em;
...;
}
- Instead of the two columns sitting side by side, they line wrapped
- columns took more than 100% of available width even though the widths are 70% and 30%
- Default behavior of the box model
- width and height specified for an element are for its content
- any padding, border, and margins are then added to that width
- The naive fix is to reduce the width of one of the columns
- e.g., 26% width for the sidebar
- on smaller viewports, the sidebar will still line-wrap
- An alternative is to use the
calc()
function to reduce the width- e.g.,
calc(30% - 3em)
- e.g.,
- Adjust the box model behavior with its
box-sizing
property- default value is
content-box
- use
border-box
- combined size of the content, padding, and border
- see:
ch03/listing-3.4.html
- default value is
/* Universal border box fix - apply to the root element */
:root {
box-sizing: border-box;
}
/* Box sizing isn't an inherited property; use the inherit keyword to force it to be */
*,
::before,
::after {
box-sizing: inherit;
}
- See:
ch03/listing-3.6.html
- This allows you to add third-party components with their own CSS to your page, especially if their CSS wasn't written with this fix in mind
- you can convert a third-party component into a
content-box
when necessary by targeting its top-level container - all elements inside the component will inherit the box sizing
- you can convert a third-party component into a
.third-party-component {
box-sizing: content-box;
}
- Add a margin to one of the columns to create a small gap (gutter) between columns
- Percent-based gutter margin:
.sidebar {
float: left;
width: 29%;
margin-left: 1%;
...;
}
- Use
calc()
to subtract the gutter from the width:
.sidebar {
float: left;
width: calc(30% - 1.5em);
margin-left: 1.5em;
...;
}
- Typically it's best to avoid setting explicit heights on elements
- Normal document flow
- refers to the default layout behavior of elements on the page
- inline elements flow along with the text of the page, from left to right, line wrapping when they reach the edge of their container
- block-level elements fall on individual lines, with a line break above and below
- is designed to work with a constrained width and an unlimited height
- height of a container is organically determined by its contents, not by the container itself
- refers to the default layout behavior of elements on the page
- When you explicitly set an element's height, you run the risk of its contents overflowing the container
- You can control the exact behavior of the overflowing content with the
overflow
property, which supports four values:visible
(default): All content is visible, even when it overflows the container's edgeshidden
: Content that overflows the container's padding edge is clipped and won't be visiblescroll
: Scrollbars are added to the container so the user can scroll to see the remaining contentauto
: Scrollbars are added to the container only if the contents overflow
- Horizontal overflow
- it's possible for content to overflow horizontally, e.g., due to a long URL in a narrow container
- you can control only horizontal overflow using the
overflow-x
property, or vertical overflow withoverflow-y
- these properties support the same values as the
overflow
property
- Specifying height using a percentage is problematic
- percentage refers to the size of an element's containing block
- the height of that container is typically determined by the height of its children
- circular definition - the browser will ignore the declaration
- For percentage-based heights to work, the parent must have an explicitly defined height
- Use the viewport-relative
vh
units to make a container fill the screen - Columns of equal height
- the best solution is for the columns to size themselves naturally, and then extend the shorter column so that its height is equal to the height of the taller one
- Instead of using floats, you'll make the container a
display: table
and each column adisplay: table-cell
- see (misaligned outer edges):
ch03/listing-3.9.html
- see (misaligned outer edges):
- Fix outer edge misalignment by using negative margins, applied to a new container that wraps around the whole table
- By applying
display: flex
to the container, it becomes a flex container- its child elements will become the same height by default
- you can set widths and margins on the items
- even though this would add up to more than a 100%, the flexbox sorts it out
- see:
ch03/listing-3.11.html
- You can use
min-height
andmax-height
to specify a minimum or maximum value, allowing the element to size naturally within those bounds min-height
means the element will be at least as high as you specify, and if the content doesn't fit, the browser will allow the element to grow naturally to prevent overflowmax-height
allows an element to size naturally, up to a point; if that size is reached, the element doesn't become any taller, and the contents will overflow- Similar properties
min-width
andmax-width
constrain an element's width
- Why doesn't
vertical-align
work?- only affects inline and table-cell elements
- inline elements
- controls alignment among other elements on the same line
- e.g., control how an inline image aligns with the neighboring text
- table-cell elements
- controls the alignment of the contents within the cell
- you can accomplish vertical centering with a CSS table layout
- A lot of the trouble comes from setting the height of a container at a constant value, and then attempting to center a dynamically sized piece of content inside it
- The simplest way to vertically center in CSS
- give a container equal top and bottom padding, and let both the container and its contents determine their height naturally
- see
ch03/listing-3.12.html
- Guide to vertical centering
- Can you use a natural height container?
- apply an equal top and bottom padding to the container to center its contents
- Do you need a specific height container, or do you need to avoid using padding?
- use
display: table-cell
andvertical-align: middle
on your container
- use
- Can you use flexbox?
- if you don't need to support IE9, you can center your content with flexbox
- see chapter 5
- Is the inner content only one line of text?
- set a tall line height equal to the desired container height
- this will force the container to grow to contain the line height
- if the contents aren't inline, you may have to set them to
inline-block
- Do you know the height of both the container and the inner content?
- center the contents with absolute positioning
- see chapter 7
- use this when all approaches mentioned here fail
- What if you don't know the height of the inner element?
- use absolute positioning in conjunction with a transform
- see chapter 15
- use this only if you've ruled out all other options
- When in doubt, see http://howtocenterincss.com
- Can you use a natural height container?
- The exact behavior of a negative margin depends on which side of the element you apply it to
- left or top
- moves the element leftward or upward, respectively
- can cause the element to overlap another element preceding it in the document flow
- right or bottom
- doesn't shift the element
- pulls in any succeeding element
- a negative bottom margin is not unlike giving the element(s) beneath it a negative top margin
- left or top
- When a block element doesn't have a specified width, it naturally fills the width of its container
- negative right margin pulls the edge of the element to the right, bringing it outside the container
- with an equal negative left margin, and both sides of the element will be extended outside the container
- allows you to resize the table layout in
ch03/listing-3.10.html
to fill the<body>
width, despite the border spacing
- When top and/or bottom margins are adjoining, they overlap, combining to form a single margin - collapsing
- The main reason for collapsed margins has to do with the spacing of blocks of text
- Paragraphs (
<p>
), by default, have a 1 em top margin and a 1 em bottom margin- applied by the user agent stylesheet
- when you stack two paragraphs, the margins collapse, overlapping to produce only 1 em of space between the two paragraphs
- Similarly so between an
<h2>
, with a bottom margin of 0.83 em, and the following paragraph- the size of the collapsed margin is equal to the largest of the joined margins
- Elements don't have to be adjacent siblings for their margins to collapse
- if you wrap the paragraph inside an extra
div
, the visual result will be the same
- if you wrap the paragraph inside an extra
- See
<h2>
,<div>
and<p>
inch03/listing-3.13.html
- Note: Margin collapsing only occurs with top and bottom margins; left and right margins don't collapse
- An element's margin collapsing outside its container typically produces an undesirable effect if the container has a background
- See
<header>
and<h1>
inch03/listing-3.13.html
- you'd want
<h1>
's margin to stay inside<header>
- fixed for the main section of the page
- margin above "Come join us!" doesn't collapse upward outside of its container
- margins of flexbox items don't collapse
- you'd want
- Padding provides another solution
- if you add top and bottom padding to the header, the margins inside it won't collapse to the outside
- see:
ch03/listing-3.14.html
- now there's no margin between the header and the main content
- Ways to prevent margins from collapsing:
- applying
overflow: auto
(or any value other than visible) to the container- the least intrusive solution
- adding a border or padding between two margins
- margins won't collapse to the outside of a container that is floated, that is an inline block, or that has an absolute or fixed position
- when using a flexbox, margins won't collapse between elements that are part of the flex layout
- also the case with grid layout
- elements with a
table-cell
display don't have a margin, so they won't collapse- also applies to
table-row
and most other table display types - exceptions are
table
,table-inline
, andtable-caption
- also applies to
- applying
- The interplay between the padding of a container and the margins of its content can be tricky to work with
- See
.button-link
inch03/listing-3.16b.html
- fix by using the adjacent sibling combinator (
+
) to target onlybutton-link
s that immediately follow otherbutton-link
s as siblings - see
.button-link+.button-link
inch03/listing-3.17.html
- fix by using the adjacent sibling combinator (
- Add a third link to the page
- see
ch03/listing-3.19.html
- you can add a top margin to the sponsorship link
- if the sidebar changes, e.g., the sponsorship link to be moved to the top, or add a new widget to the sidebar, you'll have to revisit these margins
- see
- The lobotomized owl selector:
* + *
- targets any element that immediately follows any other element
- selects all elements on the page that aren't the first child of their parent
- targets any element that immediately follows any other element
- Use the lobotomized owl to add top margins to elements throughout your page
- see:
ch03/listing-3.20.html
- unwanted side-effect: the sidebar is an adjacent sibling of the main column, it too receives a to margin
- revert sidebar top margin to 0
- see:
- Using the lobotomized owl like this is a tradeoff
- simplifies many margins throughout your page
- you have to override it in places where you don't want it to apply
- The original purpose for a float
- pull an element (often an image) to one side of its container, allowing the document flow to wrap around it
- a floated element is removed from the normal document flow and pulled to the edge of the container
- if you float multiple elements in the same direction, they'll stack alongside one another
- Base styles for a page
- Tip: It's usually easiest to lay out the large regions of a page first, then work your way to the smaller elements within
- Double container pattern
- constraining the width and centering content on a page
- placing your content inside two nested containers and then set margins on the inner container to position it within the outer one
<body>
serves as the outer container- already 100% of the page width, so you won't have to apply any new styles to it
- inside that, wrap the entire contents of the page in a
<div class="container">
- serves as the inner container
- apply a
max-width
andauto
margins to center the contents- auto left and right margins will grow to fill the available space
- see:
ch04/listing-4.3.html
- A few behaviors of floats might catch you off guard
- Float the four media boxes to the left
- see
ch04/listing-4.4.html
- white background behind page title ("Running tips"), but it stops there instead of extending down to encompass the media boxes
- see
- Unlike elements in the normal document flow, floated elements do not add height to their parent elements
- original purpose of floats: to allow text to wrap around them
- when you float an image inside a paragraph, the paragraph does not grow to contain the image
- if the image is taller than the text of the paragraph
- the next paragraph will start immediately below the text of the first
- text in both paragraphs will wrap around the float
- One way you can correct this is with the float's companion property,
clear
- if you place an element at the end of the main container and use clear, it causes the container to expand to the bottom of the floats
- see:
ch04/listing-4.5.html
clear: both
- the clearance of the generated box is set to the amount necessary to place the top border edge below the bottom outer edge of any right-floating and left-floating boxes that resulted from elements earlier in the source document
- causes this element to move below the bottom of floated elements, rather than beside them
- because this empty div itself is not floated, the container will extend to encompass it, thereby containing the floats above it as well
- Instead of adding an extra
div
to your markup, you'll use a pseudo-element::after
- you can effectively insert an element into the DOM at the end of the container, without adding it to the markup
- Clearfix
- applied to the element that contains the floats
- see:
ch04/listing-4.6.html
/* Target at the end of the container */
.clearfix::after {
display: block;
/* Content value cause the pseudo-element to appear in the document */
content: " ";
/* Clear all floats in the container */
clear: both;
}
- Inconsistency
- margins of floated elements inside won't collapse to the outside of the clearfixed container
- margins of non-floated elements will collapse as normal
- the heading "Running tips" is pressed directly against the top of the white
<main>
- Modified clearfix to contain all margins:
.clearfix::before,
.clearfix::after {
/* Prevent margins from collapsing through the pseudo elements */
display: table;
content: " ";
}
/* Only the ::after pseudo element needs to clear floats */
.clearfix::after {
clear: both;
}
- Clearfix and
display: table
display: table
in the clearfix contains margins- creation of a display-table element (or pseudo-element) implicitly creates a table row within the element and a table cell within that
- margins don't collapse through table-cell elements
- they won't collapse through a display-table pseudo element either
display: table-cell
does not have the same effect- the
clear
property only works when applied to block-level elements- a table is a block-level element, but a table cell is not
- the
display: table
to clear floats, its implied table cell to contain the margins
- Three left-floated boxes
- box 3 doesn't float all the way to the left if box 1 is taller than box 2, instead it floats up against box 1
- box 3 "catches" on the bottom corner of box 1
┌─────┐ ┌─────┐
│ 1 │ │ 2 │
│ │ └─────┘
└─────┘ ┌─────┐
│ 3 │
└─────┘
- Fix: the first element of each row needs to clear the float above it
- target with the
:nth-child()
pseudo-class selector - see:
ch04/listing-4.8.html
- target with the
/* Each new row clears the row above */
.media:nth-child(odd) {
clear: left;
}
- If you had three items per row:
.media:nth-child(3n+1)
- Only works when you know how many elements are on each row
- if the number of items can vary your best bet is to use a different layout technique such as the flexbox or inline-block elements
- Add margins to our media elements to provide a gutter between them
- the lobotomized owl will also add a top margin to every element except the first
- need to reset the top margin
- see:
ch04/listing-4.9.html
- Media object
- image on one side, and a block of text beside it
- Float the media object image to the left
- Media body extends all the way to the left, envelops the floated image
- we want to position the media body's left edge to the right of the floated image
- Block formatting context (BFC)
- a region of the page in which elements are laid out
- is part of the surrounding document flow, but it isolates its contents from the outside context
- isolation does three things for the element that establishes the BFC:
- it contains the top and bottom margins of all elements within it; they won't collapse with margins of elements outside of the block formatting context
- it contains all floated elements within it
- it doesn't overlap with floated elements outside the BFC
- applying any of the following property values to an element triggers a BFC:
float: left
orfloat: right
: anything butnone
overflow: hidden
,auto
, orscroll
: anything butvisible
display: inline-block
,table-cell
,table-caption
,flex
,inline-flex
,grid
, orinline-grid
: these are called block containersposition: absolute
orposition: fixed
- The best way to do this is often to set an
overflow
value, eitherhidden
orauto
- Note: In some circumstances, the contents from one block formatting context may still overlap the contents of another
- if the contents overflow the container (for example, the content is too wide)
- if negative margins pull the contents outside the container
- A series of class names you can add to your markup to structure portions of the page into rows and columns
- provide no visual styles, like colors or borders
- only set widths and positions of containers
- inside each of these containers, you can add new elements to visually style however you want
- general principle: put a row container around one or more column containers
- Defined to hold a certain number of columns in each row; usually 12, but can vary
- Child elements of a row may have a width anywhere from one column up to 12 columns wide
- 12: divisible by two, three, four, and six - provides a lot of flexibility
- three-column layout (three, 4-column elements)
- four-column layout (four, 3-column elements)
- asymmetrical layouts, such as a 9-column main element and a 3-column sidebar
- Markup
- each row has a row container
div
- inside that you'll place a div for each column element with a
column-n
classn
is the number of columns across the grid
- each row has a row container
- A row around each set of two media objects
- Wrap each media object within its own 6-column container
- Add clearfix to each row
- Float all columns to the left, and specify widths for each column value
- Media object doesn't need to float left anymore as the grid column does that for you
- Remove margins from the media object, and the nth-child selector that clears each row
- Add bottom padding on the container
- because you removed all margins from the media object, including the bottom margin, there's no longer a gap below the last row of media objects and the bottom of their container
- See:
- You can create gutters by adding left and right padding to each grid column
- remove top margin from all columns, overriding the lobotomized owl
- see:
ch04/listing-4.17.html
- introduces a slight misalignment between a grid column and content outside the grid row
- Fix misalignment by stretching the row to be a little wider using negative margins on the left and right sides
- Formally Flexible Box Layout
- More predictable and far more specific control than floats
- Simple solution to the long-standing problems of vertical centering and equal height columns
- One weakness - the overwhelming number of options
display: flex
turns an element into a flex container, and its direct children turn into flex items- flex items align side by side, left to right, all in one row
- flex container fills the available width like a block element
- flex items may not necessarily fill the width of their flex container
- flex items are all the same height, determined naturally by their contents
display: inline-flex
creates a flex container that behaves more like an inline-block element rather than a block- flows inline with other inline elements
- won't automatically grow to 100% width
- flex items within it generally behave the same as with
display: flex
main-start MAIN AXIS main-end
────────────────────────────────→
cross-start │ FLEX CONTAINER
│ ┌──────────────────────────────┐
│ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
CROSS AXIS │ │ │ 1 │ │ 2 │ │ 3 │ │ 4 │ │
│ │ └───┘ └───┘ └───┘ └───┘ │
│ │ FLEX ITEMS │
cross-end ↓ └──────────────────────────────┘
- Initial page and styles:
ch05/listing-5.2.html
- Flex container should be
<ul>
, its children,<li>
, the flex items- apply
display: flex
to the list - override the default list styles and the lobotomized owl top margins
- apply colors
- see:
ch05/listing-5.3.html
- apply
- Note:
- use Autoprefixer to automatically apply vendor prefixes to support older browsers
- Apply the menu item padding to the internal
<a>
elements, not the<li>
elements- the entire area that looks like a menu link to behave like a link when the user clicks it
- Make the links a display block
- if they were to remain inline, the height they'd contribute to their parent would be derived from their line height, not their padding and content
- Add space between the menu items
- apply a margin between each item, but not to the outside edges
- use the
margin-left
property and an adjacent sibling combinator,li + li
- Push last button all the way to the right
- apply an auto left margin, which causes the margin to fill all the available space
- See:
ch05/listing-5.5.html
- The
flex
property controls the size of the flex items along the main axis (width) ch05/listing-5.6.html
- white background to the three tiles via the
tile
class - flex layout to the
<main>
element by targeting theflex
class - remove top margin and apply space between the flex items
- content is nwo divided into two columns
- column widths are not yet specified, and so they size themselves naturally, based on their content
- white background to the three tiles via the
ch05/listing-5.7.html
- use
flex
to apply widths of two-thirds and one-third on the columns via thecolumn-main
andcolumn-sidebar
classes flex
property is shorthand for three different sizing properties:flex-grow
flex-shrink
flex-basis
flex: 2
is equivalent toflex: 2 1 0%
- use
- Starting point for the size of an element - an initial "main size"
- Can be set to any value that would apply to
width
, including values in px, ems, or % - Initial value is
auto
- browser will look to see if the element has a
width
declared- if declared, use that size
- if not, use the element's natural size by the contents
width
will be ignored for elements that have any flex basis other thanauto
- browser will look to see if the element has a
- Once this initial main size is established for each flex item, they may need to grow or shrink in order to fit (or fill) the flex container along the main axis
- that's where
flex-grow
andflex-shrink
come in
- that's where
- Once
flex-basis
is computed for each flex item, they (plus any margins between them) will add up to some width- may not necessarily fill the width of the flex container, leaving a remainder
- The remainder will be consumed by the flex items based on their
flex-grow
values- non-negative integer
flex-grow: 0
: won't grow past its flex basis- items with non-zero growth factor - grow until the remainder is used up, filling the width of the container
flex-grow: 2
: grow twice as much as an item withflex-grow: 1
flex: 2
andflex: 1
- flex basis of 0%, so 100% of the container's width is the remainder (minus the 1.5 em margin between the two columns)
- remainder is distributed to the two columns: two-thirds and one-third
- Favor the use of the shorthand
flex
property instead of declaring the properties individually- they are not set to their initial values when omitted
- shorthand assigns useful values for any of the 3 that you omit
- After determining the initial main size of the flex items, they could exceed the size available in the flex container - overflow
flex-shrink
indicates whether it should shrink to prevent overflow- non-negative integer
flex-shrink: 0
: don't shrink- an item with a higher value will shrink more than an item with a lower value, proportional to the
flex-shrink
values
ch05/listing-5.8.html
- two columns sizing by relying on
flex-shrink
column-main
is slightly narrower than inch05/listing-5.7.html
column-main
has padding butcolumn-sidebar
doesn't- padding changes the way the initial main size of the flex item is determined when flex-basis is 0%
column-main
fromch05/listing-5.7.html
is 3 em wider - the size of its left and right padding fromtile
- if you need your measurements to be precise, either ensure the paddings are equal or use the flex basis method
- two columns sizing by relying on
flex: none
|flex: none
|flex: none
- items grow their natural width, not necessarily filling the width of the container
flex: 0 0 300px
|flex: 1
- first item fixed width, second item fills the remainder
flex: 0 0 200px
|flex: 1
|flex: 0 0 200px
- 'holy grail' layout - first and third items with fixed width, center item grow to fill the remainder
flex: 50%
|flex: 25%
|flex: 25%
- items grow to the percentage widths specified; can be used to build a grid system
flex-direction
row
(initial value): items to flow left-to-rightcolumn
: flex items to stack vertically (top to bottom)row-reverse
: flow items right to leftcolumn-reverse
: flow items bottom to top
ch05/listing-5.9-before.html
- flex items (
column-main
andcolumn-sidebar
) are equal height, but the tiles inside the right flex item (column-sidebar
) don't grow to fill it
- flex items (
ch05/listing-5.9.html
- turn the right column (
column-sidebar
) into a flex container withflex-direction: column
- apply non-zero
flex-grow
value to both tiles within - nested flexboxes -
column-sidebar
- flex item for the outer flexbox
- flex container for the inner flexbox
- turn the right column (
flex-direction: column
- main axis is rotated, flows from top to bottom
flex-basis
,flex-grow
, andflex-shrink
now apply to the element height rather than the widthflex: 1
: height of flex item will stretch if necessary to fill the container- flex container's height is determined by its flex items
flex-grow
andflex-shrink
applied to the items will have no effect unless something else forces the height of the flex container to a specific size- that "something" is the height derived from the outer flexbox
ch05/listing-5.10.html
- styling the login form has 3 parts: heading, input fields, button
- text-like inputs:
display: block
- normally, display block elements automatically fill the available width
- but
<input>
's width is determined by thesize
attribute - force specific width with
width
- In general, you begin a flexbox as follows:
- identify a container and its items and use
display: flex
on the container - if necessary, set the
flex-direction
on the container - declare margins and/or
flex
values for the flex items where necessary to control their size - once you've put elements roughly where they belong, you can add other flexbox properties where necessary
- identify a container and its items and use
flex-direction
flex-wrap
nowrap
(initial value),wrap
,wrap-reverse
- to allow flex items to wrap to a new row
- when wrapping is enabled, the items don't shrink according to their
flex-shrink
values- any items that would overflow the flex container wrap onto a new line
- if the flex direction is
column
orcolumn-reverse
flex-wrap
will allow the flex items to overflow into a new column- only happens if something constrains the height of the container
- otherwise it grows to contain its flex items
flex-flow
- shorthand for both
flex-direction
andflex-wrap
- e.g.,
flex-flow: column wrap
- shorthand for both
justify-content
flex-start
(initial value),flex-end
,center
,space-between
,space-around
- control how items are positioned along the main axis
flex-start
- stacks items against the beginning of the main axis
- no space between them unless the items have margins specified
flex-end
- stacks the items at the end of the main axis
space-between
- puts the first flex item at the beginning of the main axis, and the last item at the end
- remaining items are positioned evenly between them
- puts the first flex item at the beginning of the main axis, and the last item at the end
space-around
- similar, but it will also add even spacing before the first item and after the last
- spacing is applied after
margins
andflex-grow
values are calculated- if any items have a non-zero
flex-grow
value, or any items have anauto
margin on the main axis, thenjustify-content
has no effect
- if any items have a non-zero
align-items
stretch
(initial value),flex-start
,flex-end
,center
,baseline
- adjust items' alignment along the cross axis
stretch
- all items to fill the container's height in a row layout, or width in a column layout
- all other values allow flex items to size themselves naturally
flex-start
andflex-end
- align items along the start or end of the cross axis (top or bottom of a row, respectively)
center
- centers the items
baseline
- align items so that the baseline of the first row of text in each flex item is aligned
- useful if you want the baseline of a header in one flex item with a large font to line up with the baseline of smaller text in the other flex items
align-content
stretch
(the initial value),flex-start
,flex-end
,center
,space-between
, andspace-around
- if you enable wrapping (using
flex-wrap
), this property controls the spacing of each row inside the flex container along the cross axis- ignored if items don't wrap
- property values apply spacing similar to
justify-content
flex-grow
flex-shrink
flex-basis
align-self
auto
(initial value),flex-start
,flex-end
,center
,stretch
,baseline
- control a flex item's alignment along its container's cross axis
- does the same thing as the flex container property
align-items
- except it lets you align individual flex items differently
auto
- defer to the container's
align-items
value
- defer to the container's
- any other value overrides the container's setting
order
- change the order the items are stacked
0
(initial value), any integer, positive or negative- it multiple flex items have the same value, they'll appear according to source order
- lowest value item is moved to the beginning of the list
ch05/listing-5.11.html
- text '$20.00' is wrapped in a
div
- flex container- 3 flex items for the 3 different parts
justify-content: center
to horizontally center the flex itemsalign-items: center
andalign-self
to control vertical alignment
- text '$20.00' is wrapped in a
- Odd behavior if your page is large or is loaded over a slow connection
- Flex sizes are calculated based on the number of flex items and the amount (and size) of content within them
- Assume you have a three-column layout, built using a flexbox (
flex-direction: row
)- as the browser loads content, it progressively renders it to the screen, even as it continues to download the remainder of the page
- if the content for two of these columns loads, the browser might render them before it loads the content for the third column
- the browser recalculates the sizes of each flex item and renders the page again
- One suggestion is to favor grid layout for the full page layout
- Grant, Keith J. CSS in depth. Shelter Island, NY: Manning Publications Co, 2018.
- "CSS Properties." CSS Infos, css-infos.net/.