Graduate Program KB

  1. Fundamentals Recap
  2. Rendering Logic I
    1. The Box Model
    2. Flow Layout
    3. Margin Collapse
  3. Rendering Logic II
    1. Relative Positioning
    2. Absolute Positioning
      1. Stacking Contexts
    3. Fixed Positioning
    4. Overflow
    5. Sticky Positioning
    6. Hidden Content
  4. Modern Component Architecture
    1. CSS Ecosystems
    2. styled-components 101
    3. Building Component Libraries with styled-components
  5. Flexbox
    1. Growing and Shrinking
    2. More on Flexbox

Fundamentals Recap

  • <link rel="stylesheet" href="<file>.css/> to add CSS to a document
  • Elements are styled using selectors and combinators:
p,
li {
  /* target elements by kind */
}

.foo {
  /* target elements assigned a class */
}

li.foo {
  /* target elements of a kind assigned a class */
}

li em {
  /* DESCENDANT COMBINATOR: Target elements nested inside another element */
}

li > em {
  /* CHILD COMBINATOR: Target immediate descendants inside another element */
}

h1 + p {
  /* NEXT SIBLING COMBINATOR: Target element that comes after an element but is in the same hierarchy level */
}
  • Media Queries: Apply conditional formatting based on viewing conditions such as screen resolution, e.g. :
@media (min-width: 300px) {
  /* only applied when  window is at least 300px wide */
}
  • Pseudo-classes allow application of style based on an element's current state:

    • :focus - Clicked-on or tabbed-to element
    • :hover - Moused-over
    • :checked - Checkbox/radio button is filled in
    • :first-child - First element of a tag/class within a container
    • :last-child - Last element of a tag/class within a container
    • :first-of-type - First of tag in document
    • :last-of-type - Last of tag in document
  • Pseudo-elements are like pseudo-classes but target sub-elements within an element rather than a specific state. Pseudo-elements do not exist on their own, but are created when they are used in a stylesheet

  • input::placeholder - Placeholder text in an input element

  • x::before - Inside x, right before x's content

  • x::after - Inside x, right after x's content

  • Color formats in CSS:

    • Name, e.g. color: red;
    • Hex codes, e.g. color: #FF0000;
    • HSL (Hue/Saturation/Lightness), e.g. color: hsl(200deg 100% 50%);
      • Can add alpha channel value like color: hsl(200deg 100% 50% / 1); where 1 represents a fully opaque colour and 0 represents an invisible colour.
  • Relevant units in CSS:

    • Pixels, e.g. width: 100px;
    • Ems (relative unit equal to font size of the current element), e.g. padding-button: 3em;
    • Rems (relative unit equal to the font-size of the root element), e.g. font-size: 2rem;. Helpful when you want text to scale consistently
    • Percentages (relative to parent element), e.g. .child {width: 50%;}
    • vw and vh (percentage of the viewport's width and height respectively). Also svw and svh which use the small viewport's dimensions.
  • Typography properties:

p {
  font-family: 'Roboto', Arial, sans-serif;
  /* Can be set to specific font or a system-default font like serif or monospace. */
  /* Web fonts imported via HTML should be surrounded in quotation marks */
  /* Multiple fonts can be specified to create a font-stack. The browser will use the first available font. */

  font-weight: bold;
  /* Can also be specified via a numbering system from 1 to 1000 for precise control: */
  font-weight: 300; /* Light, thin text */
  font-weight: 400; /* Normal text*/
  font-weight: 700; /* Heavy, bold text */

  font-style: italic;

  text-decoration: underline;

  text-align: left;

  text-transform: uppercase; /* render in ALL CAPS */

  letter-spacing: 3px; /* horizontal character gap */
  line-height: 1.5; /* vertical distance between lines */
}

nav a {
  text-decoration: none; /* remove underlines from navigation links */
}

Rendering Logic I

  • Each browser includes their own user-agent stylesheet, which defines base styles.
  • Certain properties are inherited by children.
    • You can force a property to be inherited by using the inherit value, e.g. color: inherit;
  • When style rules conflict, the rule with the most specific selector will be applied by the browser (from least to most specific: tags, classes, element IDs).
  • Documents have two dimensions: Block (perpendicular to the flow of text within a line. vertical in English) and Inline (parallel to the flow of text within a line. horizontal in English)
  • Flow-relative logical properties (via Chrome's built-in style for p tags):
p {
  display: block; /* element will be treated as a block */
  margin-block-start: 1em; /* top margin in English pages */
  margin-block-end: 1em; /* bottom margin in English pages */
  margin-inline-start: 0px; /* left margin in English pages */
  margin-inline-end: 0px; /* right margin in English pages*/
}

The Box Model

  • The four 'boxes' of an element:
    1. Content: Area where your content is displayed. Sized with props like inline-size and block-size.
    2. Padding: Sits around the content as whitespace. Sized with padding and related props
    3. Border: Wraps around content and any padding. Sized with border and related props.
    4. Margin: Outermost layer wrapping around content, padding and border as whitespace between one box and other elements. Sized using margin and related props
  • By default, size properties will set the size of the content box rather than the border box as you may expect. To change this behaviour use this snippet:
*,
*::before,
*::after {
  box-sizing: border-box;
}
  • Padding is set via a sequence of unit definitions in the order top -> right -> bottom -> left. With fewer than 4 values the browser will fill in the gaps:
    • 1 value: All sides will have same padding
    • 2 values: First value will be the padding for the top/bottom, second value will be for the left/right side
    • 3 values: Interpreted as 'top, sides, bottom'.
  • Borders have 3 styles: width, style (e.g. solid, dotted) and colour. Can be combined into a shorthand like border: 3px solid hotpink;
  • border-radius determines the radius of rounded corners on the border box. Can be set all at once or per corner e.g. border-radius: 10px 20px 30px 40px (running clockwise from top-left corner)
  • outline is like border but is a cosmetic effect that doesn't effect layout and can be used as a "second border"
    • Outlines will follow the curse set with border-radius in modern browsers
    • Outlines have an outline-offset property that sets a gap between the element and the outline
  • With padding and border only positive numbers are supported, but margin can use negative numbers to pull an element outside its parent
    • Setting a margin-left or margin-right value to auto will cause the margin to take up the maximum possible space. This works for most elements with explicit width.

Flow Layout

  • When it comes to layout, CSS is more like a collection of mini-languages than a single cohesive languages. Each HTML element has its layout calculated according to their assigned layout mode, which may be flow, table, positioned, multi-column, flexbox or grid.
  • In flow layout, every HTML tag has a default type. <div> and <header> are block elements, <span> and <a> are inline elements. Type can be toggled using the attribute display: {block|inline};
  • Inline elements will ignore any properties that would shift elements in a non-inline direction like height.
    • Replaced elements like <img/>, <video/> and <canvas/> are technically inline but can affect block layout.
  • Block elements will greedily expand to fill the entire available horizontal space. Even if width is set to fit-content, it will not share any inline space.
  • The browser treats inline elements as if they contain typography. This can result in "magic space" where, for example, images within <div> elements gain extra line-height. This can be resolved by setting display:block or line-height:0
  • HTML is, to a certain extent, space-sensitive. This can cause issues in the flow layout where whitespace between HTML elements will make images unexpectedly spaced.
  • display:inline-block will make an element behave as a block-level element that can be placed in an inline context. Can use the properties of both inline and block elements.
    • Keep in mind inline-block elements don't line-wrap

Width Algorithms::

  • By default, width calculations are done looking up the element tree.
  • Width algorithms:
    • auto: context-aware dynamic sizing that will greedily consume available space while respecting viewport constraints. Default value for block elements.
    • min-content: Element will become as narrow as it can be, based on its child contents. Will add line-breaks to text whenever whitespace or hyphenated words are encountered.
    • max-content: Element will become as wide as possible based on its child components (but does not try to fill all available space). Will never add line-breaks.
    • fit-content: Essentially the same as auto, but with a more descriptive name.
  • Width constraints can be added with min-width and max-width

Height Algorithms:

  • By default, height calculations are done looking down the element tree.
  • Avoid constraining heights, as you don't know how much space an element's content will take up.
  • To make an element take up the height of the viewport, either:
    • Put height: 100% on every element before the element and put min-height: 100% on the element. Or,
    • Put height: 100svh on the element (or height: 100vh for older browsers)

Margin Collapse

  • In certain situations margins can "collapse" and overlap.

Rules of Margin Collapse

  • Only block-level margins collapse.
  • Margins only collapse in Flow layout.
  • Margin collapses will be blocked by:
    • Elements between siblings (e.g a line break between two elements with margins)
    • Padding and borders
    • Gap created by a min-height attribute.
  • The bigger margin wins (i.e. the effective margin between two elements of different sizes will be the size of the larger margin). This is also true for negative margins (e.g. -32px will win over -16px).
  • Nesting doesn't prevent collapsing. Margins are meant to increase the distance between siblings, not the gap between a child and its parent's bounding box (which is what padding is for). Margin will always try and increase distance between siblings even if it means transferring margin to the parent element.
  • Overlapping elements can collapse in the same direction
  • More than two margins can collapse
  • Negative and positive margins will share a space equal to the sum of their margin sizes (e.g -25px + 25px = 0px collapsed).

Using Margin Effectively

  • Avoid using margin on something at the component boundary
  • Use layout components to group components with margin properties

Rendering Logic II

  • Positioned Layout: Layout that allows items to overlap.
    • Opt into positioned layout by using the positioned property, which can be set to relative, absolute, fixed or sticky. Setting positioned to static or initial will opt out of positioned layout.

Relative Positioning

  • Relative is the most subtle Positioned sub-layout, as it doesn't effect the layout of sibling elements. Does two things:
    1. Constrains certain children
    2. Enables additional CSS properties to be used
  • The additional CSS properties used includes top, left, right and bottom. These are directional values which can be used to shift the element around relative to its natural position. Can be set to negative values.
  • Relative positioning can be applied to both block and inline elements, allowing us to nudge inline elements in a way that isn't really possible otherwise.

Absolute Positioning

  • Absolute Positioning allows you to position elements wherever you want. Use it for:

    • UI elements that need to float above the UI like tooltips or dropdowns
    • Decorative elements that need to be stuck in certain positions
    • Stacking multiple elements in the same place, like a deck of cards
  • Enables the use of the edge properties top, left, right and bottom, which specify the distance it should be from each edge of the viewport

  • If you don't give an absolute element an anchor it will sit in its default in-flow position.

  • When you set an elements position to absolute, it is pulled out of the flow. When laying out elements, the browser effectively pretends absolutely-positioned elements don't exist.

  • If an element is positioned to be equidistant from each side but has been given a specific side, it will prioritize adhering to the top and left properties

  • Setting margin: auto will make an element center itself in the viewport. This requires absolute positioning, equal distances from each edge and a fixed size.

  • The inset property will set all 4 edge properties to the provided value.

  • *Containing Blocks**: Absolute elements can only be contained by other elements using Positioned layout. When deciding where to place an absolutely-positioned element, it crawls up the tree to try and find a Positioned ancestor. The first one it finds will provide the containing block, and will be positioned according to its edges ignoring padding.

Stacking Contexts

  • Default layering:
    • When all siblings are rendered in Flow layout, the DOM order controls how the background elements overlap, but the content will always float to the front
    • If one sibling uses positioned layout, it will appear above its non-positioned sibling, no matter what the DOM order is.
    • If both siblings use positioned layout, the DOM order controls which element will be on top. Unlike in Flow layout, the content does not float to the front.
  • z-index: Override default layering behaviour by assigning elements values on the z-axis (i.e. up/down). Higher z-index values are placed closer to the viewer in 3D space.
    • Negative z-index values can just confuse things.
  • Stacking Contexts: If an element is assigned a z-index, a stacking context is created for its children. z-index values will be relative other values inside the parent element, not relative to all elements in the document.
    • Think of it in terms of versioning. If a parent element has a z-index of 1 and a child element inside it has a z-index of 99999, think of it's true index as 1.99999. No matter how high the z-index of the child element is, it will never be layered above an element that is a sibling of the parent with a z-index of 2.
  • Things that create stacking contexts:
    • Setting opacity to a value less than 1
    • Setting position to fixed or sticky
    • Applying a mix-blend-mode other than normal
    • Adding a z-index to a child inside a display: flex or display: grid container
    • Using transform, filter, clip-path or perspective
    • Explicitly creating a context with isolation: isolate
  • Stacking contexts can be inspected and debugged using CSS Stacking Context Inspector.
  • Strategies for reducing z-index wars:
    • Use DOM order instead (best used on non-interactive elements, as changing DOM order also changes their order in the tab index).
    • Create isolated stacking contexts using isolation: isolate. Flattens the z-index of child elements without requiring parent elements to have a z-index.

Fixed Positioning

  • Fixed Positioned elements can only be contained by the viewport and are immune to scrolling. Perfect for overlays like modals.
  • Fixed positioning is incompatible with certain CSS properties. If an ancestor element used the transform, filter or will-change property it will behave like an absolute positioned element. Fix this by either removing/replacing the ancestor's CSS property or use a portal component.
    • To find a culprit ancestor element, run the following snippet in your browser console (ensure you've selected the correct environment if the page uses iframes):
// Replace “.the-fixed-child” for a CSS selector
// that matches the fixed-position element:
const selector = '.the-fixed-child';

function findCulprits(elem) {
  if (!elem) {
    throw new Error(
      'Could not find element with that selector'
    );
  }

  let parent = elem.parentElement;

  while (parent) {
    const {
      transform,
      willChange,
      filter,
    } = getComputedStyle(parent);

    if (
      transform !== 'none' ||
      willChange === 'transform' ||
      filter !== 'none'
    ) {
      console.warn(
        '🚨 Found a culprit! 🚨\n',
        parent,
        { transform, willChange, filter }
      );
    }
    parent = parent.parentElement;
  }
}

findCulprits(document.querySelector(selector));

Overflow

  • Overflow is a condition that happens when content doesn't fit into its parent's content box. To choose how to manage overflow situations, set the property overflow to one of the following values:
    • visible allows an element's contents to extend beyond its bounds. Default behaviour in overflow situations.
    • scroll lets users scroll through the content inside the element (adds a scroll bar).
    • auto only makes an element scrollable if the contents inside don't fit.
    • hidden truncates all content that extends beyond the bounds of the container. Essentially creates a scroll container but without a scroll bar. If the content contains focus-able elements users can tab through them to scroll through the hidden content.
    • clip truncates content that extends beyond the bounds of the container without creating a scroll container. As of November 2022, around 20% of users were using browsers that don't support overflow: clip. If the content contains focus-able elements, users can tab through them and eventually lose the focus indicator.
  • To manage both vertical and horizontal overflow, use overflow-y and overflow-x respectively. overflow is essentially a shorthand that sets both properties to the same value.
    • To make only one side (vertical or horizontal) hidden, create a wrapper class and set overflow-y: hidden or overflow-x: hidden
  • To instruct a container to not linewrap for overflow content, set white-space: nowrap
  • Overflow settings only apply to positioned children if their parent is also positioned.
  • Fixed-positioned elements are immune from being hidden with overflow:hidden

Sticky Positioning

  • Sticky Positioning: As you scroll, an element can "stick" to the edge. The moment the element reaches the edge of the viewport it transitions from being relatively-positioned to being fixed-positioned.
  • Sticky elements only stick while their container is in view.
  • Edge properties can be set on sticky elements to define how far the element can be from the edge of the viewport before it starts to stick. Can be set to negative numbers.
  • Sticky elements take up space in the initial layout. Even when the element is stuck to the edge during scrolling the space remains and overall layout is unaffected.
  • Common reasons an element won't stick:
    • A parent is hiding/managing overflow
    • The container isn't big enough
    • The sticky element is stretched
  • If there's a thin gap above your sticky header, it may be due to a rounding issue with fractional pixels. Solve it with <edge>: -1px.

Hidden Content

  • display: none
  • visibility: none: Useful when you want visibility to be selectively undone by children. Undo using visibility: visible
  • opacity: 0: Use when an item needs to be semi-visible, or an item's visibility needs to animated. Elements with 0 opacity are still interactive.
  • To make an element hidden from screens but still discoverable for people using screen readers, use this snippet:
.visually-hidden {
  position: absolute;
  overflow: hidden;
  clip: rect(0 0 0 0);
  height: 1px;
  width: 1px;
  margin: -1px;
  padding: 0;
  border 0;
}
  • To make an element hidden from screen-readers but visible on screens set the aria-hidden attribute to true on the HTML element. To indicate to screen readers that they should ignore interactive content add the inert attribute as well.

Modern Component Architecture

CSS Ecosystems

Vanilla CSS

  • PROS
    • No tooling means less complexity, no runtime performance costs
    • Modern CSS features like CSS custom properties make certain tooling features (eg. Sass variables) redundant
  • CONS
    • Global and unscoped. The CSS you write in one place will be applied everywhere. Using a naming convention like BEM can help, at scale naming collisions are still possible.
    • Requires that you remember to add vendor prefixes for many CSS properties to ensure optimal browser support
    • Can't share data easily between CSS and JS
    • Made for documents, not apps. Awkward to use in modern JS application development.

Sass

  • Sass is a preprocessor that compiles to vanilla CSS that extends CSS with features like nesting, variables and iteration.
  • PROS
    • Includes powerful tools like for-loops, mixins and nesting
    • High developer satisfaction compared with vanilla CSS
  • CONS
    • Requires a build step
    • Remains global by nature and isn't scoped to specific components.
    • As everything happens at build time, you can't react to things in real-time, so Sass variables are nowhere near as powerful as CSS variables.
    • Requires native dependencies that can fail or get out-of-date.
    • Naming clashes with CSS
    • Is becoming less popular in the JS scene

Aphrodite

  • Aphrodite is a React-Native-like styling solution to he web. Styles are written in JS and used by React components.
  • PROS
    • No more scoping and specificity issues.
    • Allows you to use JS within your CSS, making it easy to share state and also allows for complex iteration and generation without the need to learn a new Domain-Specific Language (DSL) as you would with Sass
    • Encourages good habits (no support for nesting)
    • Automatically adds vendor prefixes
    • Similar API to React Native makes it easy to move between projects or possibly port components between them.
    • No need to tab between files when working with files and JSX
  • CONS
    • Requires a build step
    • High-friction
    • Has a cost in terms of bundle size and runtime execution time
    • Styles must be written in JS. Property names are camelCased, values must be quoted.
    • Writing global styles is unintuitive
    • Not a very active project

CSS Modules

  • CSS Modules is a tool that allows you to write vanilla CSS and import it into a JS file.
  • PROS
    • No more scoping and specificity. Classes you write will be globally unique, even if a different CSS file has a class with the same name.
    • Feels like writing normal CSS
    • Offers a composes features, to extend existing CSS classes
  • CONS
    • Doesn't really offer any modern convenience features like autoprefixing
    • Hard to share data between CSS and JS

Single-file components are a way to create scoped CSS in the same file as your component definition offered by Vue and Svelte.

styled-components

  • styled-components are a CSS-in-JS solution, where every style is a React component
  • PROS
    • Solves scoping and specificity in a way that fits well with component-driven architectures.
    • Feels like writing CSS with some quality-of-life improvements borrowed from Sass.
    • Offers good solutions for animations and global styles
    • High developer satisfaction
    • Highly performant
    • Currently the most popular CSS-in-JS solution
  • CONS
    • Requires a build system
    • Primary a React tool
    • Obfuscates the underlying markup tags, which can make it harder to get a sense of the HTML semantics at a glance
  • Emotion is a similar solution with largely the same API.

Tailwind

  • Tailwind is a utility-first CSS framework (utility meaning a short CSS class that maps to specific styles).
  • PROS
    • Solves scoping and specificity
    • Includes built-in tokens which can make it easier to come up with a nice design
    • Can be faster to write
    • Not React-specific
    • Has exploded in popularity recently, meaning better community support
  • CONS
    • Relatively steep learning curve compared to other tools
    • Because not all CSS can be turned into utilities, you'll likely need a secondary system for writing traditional CSS.
    • Adds a lot of hard-to-read "bulk" to your markup if many classes are required.

styled-components 101

  • styled-components uses tagged template literals. To create a style, call the method for the HTML tag you're using on the styled object imported from styled-components, e.g.
import styled from 'styled-components';

const Button = styled.button`
  display: flex;

  /* & will be automatically replaced with a unique vendor prefix */
  &:hover {
    color: red;
  }
`;
  • The above statement produces the following CSS:
.abc123 {
  /* Vendor prefixes for legacy browsers: */
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}

.abc123::hover {
  color: red;
}
  • styled has methods for every HTML tag typically used within the <body>
  • Once a style has been declared, style a component by wrapping the body of the tag in the style component, e.g. <div><StyledDiv>{children}</StyledDiv></div>
  • Styles can also be written by passing a string of css to the css prop. Requires importing (babel-plugin-styled-components)
  • To create global styles:
import { createGlobalStyle } from 'styled-components';

const GlobalStyles = createGlobalStyle`
  /* ...css... */
`

function App() {
  return <>
     // ..JSX...
     <GlobalStyles/>
  </>
}
  • To create dynamic styles, either use CSS variables (covered later in the course) or pass in values as props:
const Button = ({ color, onClick, children }) => {
  return (
    <Wrapper onClick = {onClick} style = {{ color }}>
      {children}
    </Wrapper>
  );
}

const Wrapper = styled.button`
  color: ${props => props.color}; // used color passed as prop
  padding: 16px 24px;
`
  • To create component variants:
// Assume FillButton, OutlineButton, GhostButton have been written or imported in this file

const Button ({ variant, size, children, className }) => {
  const styles = SIZES[size];

  let Component;
  switch(variant) {
    case "fill":
      Component = FillButton;
      break;
    case "outline":
      Component = OutlineButton;
      break;
    case "ghost":
      Component = GhostButton;
      break;
    default:
      throw new Error(`Unrecognized Button variant: ${variant}`);
  }

  return (
    <Component style={styles} className={className}>
      {children}
    </Component>
  )
}
  • Inversion of control nesting is a way of allowing components to take on different styles in different contexts without needing to define variants. Good for ensuring each component has a single source of styles. eg.
const TextLink = styled.a`
  /* Standard styles: */
  color: blue;
  text-decoration: none;

  /* Styles when rendered inside a quote: */
  ${QuoteContent} & {
    color: black;
    text-decoration: revert;
  }
`

Building Component Libraries with styled-components

  • Component Library: Collection of generic, reusable components that can be dropped in to multiple applications. Ensures consistency between products and can help boost new development speed as you don't have to build everything from scratch.

  • Design system: Like a component library, but made up of a collection of vector graphics instead of components.

    • Also consists of design tokens, specifying values for scales for sizes or colours.
  • Components can be composed like so:

const Base = styled.button`
  font-size: 21px;
`;

const PrimaryButton = styled(Base)`
  background: blue;
  color: white;
`
  • The as prop can be used to dynamically change the tag that styled-components renders, eg.
function Button({ href, children }) {
  return (
    // Despite 'wrapper' being set up as a button component, "as" makes sure React renders it as an anchor instead without changing its appearance on the page
    <Wrapper as="a" href={href}>
      {children}
    </Wrapper>
  )
}

const Wrapper = styled.button`
  /* ..CSS.. */
`
  • Escape Hatches are tools that allow developers to break free of constraints that are usually good to have around.
  • When building reusable components, it should be easy to follow the convention, and hard (but possible) to break free of it.
    • For commonly used components/component variants the API should be very simple. Creating one-off special components (eg. themed component variants used on certain holidays) should be possible, but be a higher-friction process.

Flexbox

  • Flexbox is a CSS layout mode that is handy when you have a set of elements and you want to control their distribution along a primary axis either horizontally or vertically.
    • If you want to control distribution of elements across two dimensions use CSS grid. Flexbox is more suited to single dimension distribution.
    • Toggle on for an element's children by applying display: flex
  • Works across two axes. Elements are distributed across the primary axis (set with flex-direction) and greedily stretch to fill space in the perpendicular cross axis
  • flex-direction sets the primary axis for flexbox elements, the axis that elements will be distributed across (either row or column). The other axis becomes the secondary/cross axis
  • justify-content configures layout in regards to the primary axis. Values:
    • flex-start - Pack items at start of primary axis
    • flex-end - Pack items at end of primary axis
    • center - Pack items at center of primary axis
    • space-between - Distribute elements evenly across the entire primary axis by putting gaps between them
    • space-around - Distribute elements evenly across the primary axis by putting gaps between elements, with half gaps at the start and end
    • space-evenly - Distribute elements across the primary axis by putting gaps between elements and at the start and end
  • align-items configures layout in regards to the cross axis.
    • stretch - Auto-sized items will enlarge to fill their container
    • flex-start - Align items against the start of the axis
    • flex-end - Align items against the end of the axis
    • align-items - Center items within axis
    • baseline - Align the bottom of each element with each other
  • align-self allows a child to have a specific alignment

Growing and Shrinking

  • There are two important sizes when dealing with Flexbox:
    • Minimum content size is the smallest an item can get without its contents overflowing
    • Hypothetical size is the value set with flex-basis, or with width for flex rows and height for flex columns (flex-basis takes precedence)
  • flex-grow sets the ratio of available space children are allowed to consume in a container. Default is 1. Higher values let elements consume more space from other elements.
  • flex-shrink sets the ratio of available space other items can consume. Cannot be used to shrink an item below its minimum content size. Default is 1, higher values let other elements consume more space from the set element
    • Setting flex-shrink to 0 ensures an element's space will never be consumed by other elements
  • flex works as a shorthand for assigning flex values.
    • flex: <flex-grow-val> <flex-shrink-val> <flex-basis-length>
    • A very common gotcha is that when you use this shorthand without assigning all values flex-basis will be by default set to 0 which overrides any width you set.
  • min-width/min-height/max-width/max-height can be used to clamp growth of elements

More on Flexbox

  • flex-wrap, when set to wrap, will enable line-wrapping of flow elements if their container's size falls below its flex-basis value.
  • gap will set a gap between flex elements, regardless of grow/shrink rules in place
  • Direction is usually dictated by DOM order, but the flexbox layout can change the visual order by setting flex-direction to row-reverse or column-reverse

Layout Interactions

  • When there's a conflict between layout modes, positioned layout will always win out. Flexbox containers with positioned children will behave as if they didn't have those children (😔)
  • As a general rule, elements can't participate in multiple layout modes at once
    • Exceptions include relative and sticky positioned elements, as they inherit the origin points from their layout contexts