Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ninety-hotels-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cloudfour/patterns': major
---

Use `clamp` instead of media queries to simplify fluid logic.
8 changes: 4 additions & 4 deletions src/base/_typography.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
*/

html {
@include fluid.font-size(
breakpoint.$xs,
breakpoint.$xl,
font-size: fluid.fluid-clamp(
ms.step(0, 1rem),
ms.step(1, 1rem)
ms.step(1, 1rem),
breakpoint.$xs,
breakpoint.$xl
); /* 1 */
line-sizing: normal; /* 2 */
}
Expand Down
24 changes: 12 additions & 12 deletions src/components/card/card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,29 @@ $_focus-overflow: (size.$edge-large * -1);
/**
* The main card container
*
* 1. We use `minmax(0, auto)` to prevent these rows from displaying in some
* 1. We define our column gap here instead of in the `c-card--horizontal`
* modifiers so we don't have to define it within multiple media queries.
* 2. We use `minmax(0, auto)` to prevent these rows from displaying in some
* browsers even if their elements are nonexistent.
* 2. This allows our `c-card__link` pseudo element to position itself relative
* 3. This allows our `c-card__link` pseudo element to position itself relative
* to this container.
* 3. We define our column gap here instead of in the `c-card--horizontal`
* modifiers so we don't have to define it within multiple media queries.
*/

.c-card {
display: grid;
grid-column-gap: fluid.fluid-clamp(
size.$spacing-gap-fluid-min,
size.$spacing-gap-fluid-max,
breakpoint.$s,
breakpoint.$xl
); /* 1 */
grid-template-areas:
'cover'
'header'
'content'
'footer';
grid-template-rows: minmax(0, auto) minmax(0, auto) 1fr minmax(0, auto); /* 1 */
position: relative; /* 2 */
@include fluid.grid-column-gap(
breakpoint.$s,
breakpoint.$xl,
size.$spacing-gap-fluid-min,
size.$spacing-gap-fluid-max
); /* 3 */
grid-template-rows: minmax(0, auto) minmax(0, auto) 1fr minmax(0, auto); /* 2 */
position: relative; /* 3 */
}

.c-card--contained {
Expand Down
21 changes: 11 additions & 10 deletions src/components/sky-nav/sky-nav.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ $_masthead-height-sm: ms.step(7);
/**
* Fluidly add more vertical whitespace as the viewport width increases
*/
@include fluid.padding-block(
$_breakpoint-wide,
$_breakpoint-grow-max,
$_grow-vertical-min,
$_grow-vertical-max,
false
);
@media (min-width: $_breakpoint-wide) {
padding-block: fluid.fluid-clamp(
$_grow-vertical-min,
$_grow-vertical-max,
$_breakpoint-wide,
$_breakpoint-grow-max
);
}
}

/**
Expand Down Expand Up @@ -184,10 +185,10 @@ $_masthead-height-sm: ms.step(7);
transition: opacity transition.$slow ease.$out,
transform transition.$quick ease.$out;
width: fluid.fluid-calc(
breakpoint.$s,
breakpoint.$l,
ms.step(7),
ms.step(9) /* 3 */
ms.step(9),
/* 3 */ breakpoint.$s,
breakpoint.$l
);
@media (min-width: breakpoint.$l) {
width: ms.step(8);
Expand Down
220 changes: 56 additions & 164 deletions src/mixins/_fluid.scss
Original file line number Diff line number Diff line change
@@ -1,174 +1,66 @@
@use 'unit';

/**
* Mixins and functions for dynamically adjusting a CSS property from a minimum
* value to a maximum, starting at a minimum breakpoint width and capping at a
* maximum breakpoint.
*
* Similar to Bootstrap's RFS, except it's mobile-first and only contains the
* logic we need.
*
* @see https://blog.typekit.com/2016/08/17/flexible-typography-with-css-locks/
* @see https://betterwebtype.com/articles/2019/05/14/the-state-of-fluid-web-typography/
* @see https://github.com/twbs/rfs
*/

/**
* Although the `calc` statement is only part of the equation, breaking it into
* its own function makes it easier to add more fluid mixins in the future.
*
* 1. `$min-width` and `$max-width` should be in `em` units to avoid cross-
* browser inconsistencies with `rem` units in some browsers. But we need to
* convert the `min-width` value to `rem` so the `calc` won't be influenced
* by the current `font-size`, which would cause the fluid transformation to
* fall out of step with the viewport.
*
* @see https://zellwk.com/blog/media-query-units/
*/

@function fluid-calc($min-width, $max-width, $min, $max) {
@use '../compiled/tokens/scss/breakpoint';

/// This file contains functions for dynamically adjusting a CSS value from a
/// minimum amount to a maximum, starting from a minimum breakpoint width and
/// capping at a maximum width.
///
/// This is similar to Bootstrap's RFS, except that it's mobile-first and uses
/// the `clamp` function so as not to rely on media queries.
///
/// @link https://blog.typekit.com/2016/08/17/flexible-typography-with-css-locks/
/// @link https://betterwebtype.com/articles/2019/05/14/the-state-of-fluid-web-typography/
/// @link https://github.com/twbs/rfs

/// Generate a fluid `calc` function. Note that this won't cap the value on its
/// own: In most cases, you will want `fluid-clamp` instead.
///
/// @link https://zellwk.com/blog/media-query-units/
/// @param {Number} $min - The minimum amount.
/// @param {Number} $max - The maximum amount.
/// @param {Number} $min-width [breakpoint.$s] - The minimum viewport width in ems.
/// @param {Number} $max-width [breakpoint.$xl] - The maximum viewport width in ems.
/// @return CSS calc function.
@function fluid-calc(
$min,
$max,
$min-width: breakpoint.$s,
$max-width: breakpoint.$xl
) {
$delta: unit.strip($max - $min);
$delta-width: unit.strip($max-width - $min-width);
$min-width-rem: unit.swap($min-width, rem); /* 1 */
// We need to convert the `min-width` value to `rem` so the `calc` won't be
// influenced by the current `font-size`, which would cause the fluid
// transformation to fall out of step with the viewport.
$min-width-rem: unit.swap($min-width, rem);

@return calc(
#{$min} + #{$delta} * ((100vw - #{$min-width-rem}) / #{$delta-width})
);
}

/**
* Fluid properties
*/

@mixin column-gap($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
column-gap: $min;
}

@media (min-width: $min-width) {
column-gap: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
column-gap: $max;
}
}

@mixin font-size($min-width, $max-width, $min, $max) {
font-size: $min;

@media (min-width: $min-width) {
font-size: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
font-size: $max;
}
}

@mixin grid-gap($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
grid-gap: $min;
}

@media (min-width: $min-width) {
grid-gap: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
grid-gap: $max;
}
}

@mixin grid-column-gap($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
grid-column-gap: $min;
}

@media (min-width: $min-width) {
grid-column-gap: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
grid-column-gap: $max;
}
}

@mixin grid-row-gap($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
grid-row-gap: $min;
}

@media (min-width: $min-width) {
grid-row-gap: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
grid-row-gap: $max;
}
}

@mixin margin-inline($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
margin-inline-end: $min;
margin-inline-start: $min;
}

@media (min-width: $min-width) {
margin-inline-end: fluid-calc($min-width, $max-width, $min, $max);
margin-inline-start: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
margin-inline-end: $max;
margin-inline-start: $max;
}
}

@mixin padding($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
padding: $min;
}

@media (min-width: $min-width) {
padding: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
padding: $max;
}
}

@mixin padding-block($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
padding-block-end: $min;
padding-block-start: $min;
}

@media (min-width: $min-width) {
padding-block-end: fluid-calc($min-width, $max-width, $min, $max);
padding-block-start: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
padding-block-end: $max;
padding-block-start: $max;
}
}

@mixin padding-inline($min-width, $max-width, $min, $max, $include-min: true) {
@if $include-min {
padding-inline-end: $min;
padding-inline-start: $min;
}

@media (min-width: $min-width) {
padding-inline-end: fluid-calc($min-width, $max-width, $min, $max);
padding-inline-start: fluid-calc($min-width, $max-width, $min, $max);
}

@media (min-width: $max-width) {
padding-inline-end: $max;
padding-inline-start: $max;
}
/// Generate a fluid `clamp` function. Unlike `fluid-calc`, this will prevent
/// the value from going below `$min` or above `$max`.
///
/// @param {Number} $min - The minimum amount.
/// @param {Number} $max - The maximum amount.
/// @param {Number} $min-width [breakpoint.$s] - The minimum viewport width in ems.
/// @param {Number} $max-width [breakpoint.$xl] - The maximum viewport width in ems.
/// @return CSS clamp function.
@function fluid-clamp(
$min,
$max,
$min-width: breakpoint.$s,
$max-width: breakpoint.$xl
) {
$val: fluid-calc($min, $max, $min-width, $max-width);

// Negative ranges are useful for fluid negation, such as negative padding
// that breaks out of a container's padding. To support this, we need to swap
// $min and $max when $min is greater.
@if $min > $max {
@return clamp(#{$max}, #{$val}, #{$min});
}

@return clamp(#{$min}, #{$val}, #{$max});
}
8 changes: 4 additions & 4 deletions src/mixins/_headings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ $size-tokens: meta.module-variables('size');
// If tokens were found...
@if $min-size and $max-size {
// Output a fluid font size
@include fluid.font-size(
breakpoint.$xs,
breakpoint.$l,
font-size: fluid.fluid-clamp(
$min-size,
$max-size
$max-size,
breakpoint.$xs,
breakpoint.$l
);

// Line heights above standard heading levels should be tighter
Expand Down
12 changes: 6 additions & 6 deletions src/objects/bio/bio.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@

.o-bio {
display: grid;
grid-gap: fluid.fluid-clamp(
size.$spacing-gap-fluid-min,
size.$spacing-gap-fluid-max,
breakpoint.$s,
breakpoint.$xl
);
grid-template-areas:
'avatar'
'content'
'meta';
grid-template-rows: repeat(3, minmax(0, auto));
@include fluid.grid-gap(
breakpoint.$s,
breakpoint.$xl,
size.$spacing-gap-fluid-min,
size.$spacing-gap-fluid-max
);

@media (min-width: breakpoint.$l) {
grid-template-areas:
Expand Down
Loading