Skip to content
Closed
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
563 changes: 275 additions & 288 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@
},
"devDependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/markdown-remark": "^6.3.6",
"@astrojs/mdx": "^4.3.5",
"@astrojs/markdown-remark": "^6.3.7",
"@astrojs/mdx": "^4.3.6",
"@astrojs/prism": "^3.3.0",
"@astrojs/sitemap": "^3.6.0",
"@babel/cli": "^7.28.3",
Expand All @@ -126,7 +126,7 @@
"@types/js-yaml": "^4.0.9",
"@types/mime": "^4.0.0",
"@types/prismjs": "^1.26.5",
"astro": "^5.13.9",
"astro": "^5.14.1",
"astro-auto-import": "^0.4.4",
"autoprefixer": "^10.4.21",
"bundlewatch": "^0.4.1",
Expand All @@ -146,7 +146,7 @@
"htmlparser2": "^10.0.0",
"image-size": "^2.0.2",
"ip": "^2.0.1",
"jasmine": "^5.10.0",
"jasmine": "^5.11.0",
"jquery": "^3.7.1",
"js-yaml": "^4.1.0",
"karma": "^6.4.4",
Expand All @@ -169,7 +169,7 @@
"rehype-autolink-headings": "^7.1.0",
"remark": "^15.0.1",
"remark-html": "^16.0.1",
"rollup": "^4.52.0",
"rollup": "^4.52.3",
"rollup-plugin-istanbul": "^5.0.0",
"rtlcss": "^4.3.0",
"sass": "1.78.0",
Expand All @@ -180,7 +180,7 @@
"terser": "^5.44.0",
"unist-util-visit": "^5.0.0",
"vnu-jar": "24.10.17",
"zod": "^4.1.9"
"zod": "^4.1.11"
},
"files": [
"dist/{css,js}/*.{css,js,map}",
Expand Down
29 changes: 15 additions & 14 deletions scss/mixins/_breakpoints.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {
$n: index($breakpoint-names, $name);
@if not $n {
@error "breakpoint `#{$name}` not found in `#{$breakpoints}`";
@error "breakpoint `#{$name}` not found in `#{$breakpoint-names}`";
}
@return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
}
Expand All @@ -31,18 +31,19 @@
@return if($min != 0, $min, null);
}

// Maximum breakpoint width.
// The maximum value is reduced by 0.02px to work around the limitations of
// `min-` and `max-` prefixes and viewports with fractional widths.
// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max
// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.
// See https://bugs.webkit.org/show_bug.cgi?id=178261
// Maximum breakpoint width for range media queries.
// Returns the breakpoint value to use as an upper bound in range queries.
//
// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// 767.98px
// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// 576px
// >> breakpoint-max(xxl, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// null
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
@if $name == null {
@return null;
}
$max: map-get($breakpoints, $name);
@return if($max and $max > 0, $max - .02, null);
@return if($max and $max > 0, $max, null);
}

// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.
Expand All @@ -61,7 +62,7 @@
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
$min: breakpoint-min($name, $breakpoints);
@if $min {
@media (min-width: $min) {
@media (width >= $min) {
@content;
}
} @else {
Expand All @@ -74,7 +75,7 @@
@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
$max: breakpoint-max($name, $breakpoints);
@if $max {
@media (max-width: $max) {
@media (width < $max) {
@content;
}
} @else {
Expand All @@ -89,7 +90,7 @@
$max: breakpoint-max($upper, $breakpoints);

@if $min != null and $max != null {
@media (min-width: $min) and (max-width: $max) {
@media (width >= $min) and (width < $max) {
@content;
}
} @else if $max == null {
Expand All @@ -112,7 +113,7 @@
$max: breakpoint-max($next, $breakpoints);

@if $min != null and $max != null {
@media (min-width: $min) and (max-width: $max) {
@media (width >= $min) and (width < $max) {
@content;
}
} @else if $max == null {
Expand Down
95 changes: 95 additions & 0 deletions scss/tests/mixins/_breakpoints.test.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
@import 'true';
@import '../../mixins/breakpoints';

// Test breakpoint functions and mixins for range media query syntax

@include test-module('Breakpoint Functions') {
$test-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
);

@include test('breakpoint-max with range syntax') {
@include assert-equal(breakpoint-max(xs, $test-breakpoints), null);
@include assert-equal(breakpoint-max(sm, $test-breakpoints), 576px);
@include assert-equal(breakpoint-max(md, $test-breakpoints), 768px);
@include assert-equal(breakpoint-max(lg, $test-breakpoints), 992px);
@include assert-equal(breakpoint-max(xl, $test-breakpoints), 1200px);
@include assert-equal(breakpoint-max(xxl, $test-breakpoints), 1400px);
}
}

@include test-module('Media Query Mixins - Range Syntax') {
$test-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
);

@include test('media-breakpoint-up generates range syntax') {
@include assert {
@include output {
@include media-breakpoint-up(sm, $test-breakpoints) {
.test { color: red; }
}
}
@include expect {
@media (width >= 576px) {
.test { color: red; }
}
}
}
}

@include test('media-breakpoint-down generates range syntax') {
@include assert {
@include output {
@include media-breakpoint-down(md, $test-breakpoints) {
.test { color: blue; }
}
}
@include expect {
@media (width < 768px) {
.test { color: blue; }
}
}
}
}

@include test('media-breakpoint-between generates range syntax') {
@include assert {
@include output {
@include media-breakpoint-between(sm, lg, $test-breakpoints) {
.test { color: green; }
}
}
@include expect {
@media (width >= 576px) and (width < 992px) {
.test { color: green; }
}
}
}
}

@include test('media-breakpoint-only generates range syntax') {
@include assert {
@include output {
@include media-breakpoint-only(md, $test-breakpoints) {
.test { color: yellow; }
}
}
@include expect {
@media (width >= 768px) and (width < 992px) {
.test { color: yellow; }
}
}
}
}
}
4 changes: 2 additions & 2 deletions scss/tests/utilities/_api.test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ $utilities: ();
font-size: 1.25rem !important;
}

@media (min-width: 333px) {
@media (width >= 333px) {
.padding-sm-1rem {
padding: 1rem !important;
}
}

@media (min-width: 666px) {
@media (width >= 666px) {
.padding-md-1rem {
padding: 1rem !important;
}
Expand Down
1 change: 0 additions & 1 deletion site/src/content/callouts/info-mediaqueries-breakpoints.md

This file was deleted.

28 changes: 13 additions & 15 deletions site/src/content/docs/layout/breakpoints.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,19 @@ These Sass mixins translate in our compiled CSS using the values declared in our
// No media query for `xs` since this is the default in Bootstrap

// Small devices (landscape phones, 576px and up)
@media (min-width: 576px) { ... }
@media (width >= 576px) { ... }

// Medium devices (tablets, 768px and up)
@media (min-width: 768px) { ... }
@media (width >= 768px) { ... }

// Large devices (desktops, 992px and up)
@media (min-width: 992px) { ... }
@media (width >= 992px) { ... }

// X-Large devices (large desktops, 1200px and up)
@media (min-width: 1200px) { ... }
@media (width >= 1200px) { ... }

// XX-Large devices (larger desktops, 1400px and up)
@media (min-width: 1400px) { ... }
@media (width >= 1400px) { ... }
```

### Max-width
Expand All @@ -110,30 +110,28 @@ We occasionally use media queries that go in the other direction (the given scre
}
```

These mixins take those declared breakpoints, subtract `.02px` from them, and use them as our `max-width` values. For example:
These mixins use the breakpoint values to create `max-width` media queries using modern range syntax. For example:

```scss
// `xs` returns only a ruleset and no media query
// ... { ... }

// `sm` applies to x-small devices (portrait phones, less than 576px)
@media (max-width: 575.98px) { ... }
@media (width < 576px) { ... }

// `md` applies to small devices (landscape phones, less than 768px)
@media (max-width: 767.98px) { ... }
@media (width < 768px) { ... }

// `lg` applies to medium devices (tablets, less than 992px)
@media (max-width: 991.98px) { ... }
@media (width < 992px) { ... }

// `xl` applies to large devices (desktops, less than 1200px)
@media (max-width: 1199.98px) { ... }
@media (width < 1200px) { ... }

// `xxl` applies to x-large devices (large desktops, less than 1400px)
@media (max-width: 1399.98px) { ... }
@media (width < 1400px) { ... }
```

<Callout name="info-mediaqueries-breakpoints" type="warning" />

### Single breakpoint

There are also media queries and mixins for targeting a single segment of screen sizes using the minimum and maximum breakpoint widths.
Expand All @@ -150,7 +148,7 @@ There are also media queries and mixins for targeting a single segment of screen
For example the `@include media-breakpoint-only(md) { ... }` will result in :

```scss
@media (min-width: 768px) and (max-width: 991.98px) { ... }
@media (width >= 768px) and (width < 992px) { ... }
```

### Between breakpoints
Expand All @@ -166,5 +164,5 @@ Which results in:
```scss
// Example
// Apply styles starting from medium devices and up to extra large devices
@media (min-width: 768px) and (max-width: 1199.98px) { ... }
@media (width >= 768px) and (width < 1200px) { ... }
```