From f11ece4b94d9fd23738d1c572bd28f5197a90e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kuna?= <1282324+codecalm@users.noreply.github.com> Date: Fri, 14 Aug 2026 01:15:54 +0200 Subject: [PATCH] Add `bg-pattern-opacity-*` utilities; patterns no longer draw borders (#2873) --- .changeset/pattern-opacity-css.md | 7 + core/scss/_utilities.scss | 7 - core/scss/_variables.scss | 12 ++ core/scss/ui/_patterns.scss | 137 +++++------------- .../ui/utilities/background-patterns.mdx | 50 ++++++- preview/pages/patterns.astro | 65 ++++++++- .../pages/background-pattern-colors.astro | 2 +- .../pages/background-pattern-utilities.astro | 2 +- shared/ui/BackgroundPattern.astro | 2 +- 9 files changed, 167 insertions(+), 117 deletions(-) create mode 100644 .changeset/pattern-opacity-css.md diff --git a/.changeset/pattern-opacity-css.md b/.changeset/pattern-opacity-css.md new file mode 100644 index 000000000..016034ffb --- /dev/null +++ b/.changeset/pattern-opacity-css.md @@ -0,0 +1,7 @@ +--- +"@tabler/core": minor +"@tabler/docs": patch +"@tabler/preview": patch +--- + +Added `--pattern-opacity-factor` and `.bg-pattern-opacity-*` utilities for background patterns. diff --git a/core/scss/_utilities.scss b/core/scss/_utilities.scss index f1e16722e..d73e25014 100644 --- a/core/scss/_utilities.scss +++ b/core/scss/_utilities.scss @@ -564,13 +564,6 @@ $utilities: map.merge( class: column-gap, values: $spacers, ), - 'bg-pattern': ( - property: background, - class: bg-pattern, - values: ( - transparent: #{url-svg('')} repeat center/16px 16px, - ), - ), 'bg-gradient': ( property: background, class: bg-gradient, diff --git a/core/scss/_variables.scss b/core/scss/_variables.scss index cc37c5c01..bc4691d78 100644 --- a/core/scss/_variables.scss +++ b/core/scss/_variables.scss @@ -2191,6 +2191,18 @@ $pattern-size-sm: 0.25rem !default; $pattern-size-md: 0.5rem !default; $pattern-size-lg: 0.75rem !default; $pattern-size-xl: 1rem !default; +$pattern-opacity: 10% !default; +$pattern-opacity-factor: 1 !default; +$pattern-opacity-lighter: 6% !default; +$pattern-opacity-light: 8% !default; +$pattern-opacity-dark: 20% !default; +$pattern-opacity-darker: 50% !default; +$pattern-opacities: ( + lighter: $pattern-opacity-lighter, + light: $pattern-opacity-light, + dark: $pattern-opacity-dark, + darker: $pattern-opacity-darker, +) !default; // Markdown $markdown-heading-margin-top: 2.5rem !default; diff --git a/core/scss/ui/_patterns.scss b/core/scss/ui/_patterns.scss index 68a43918c..a8c391ea3 100644 --- a/core/scss/ui/_patterns.scss +++ b/core/scss/ui/_patterns.scss @@ -1,180 +1,128 @@ @use '../config' as *; -.bg-pattern-diagonal { +@mixin pattern-base($opacity: $pattern-opacity) { --pattern-color: var(--body-color); --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); - background-image: repeating-linear-gradient(-45deg, var(--pattern-fill) 0 1px, transparent 0 50%); + --pattern-opacity: calc(var(--pattern-opacity-factor, #{$pattern-opacity-factor}) * #{$opacity}); + --pattern-fill: color-mix(in oklch, var(--pattern-color) var(--pattern-opacity), transparent); background-clip: padding-box; +} + +.bg-pattern-transparent { + @include pattern-base(); + background-image: repeating-conic-gradient(var(--pattern-fill) 0% 25%, transparent 0% 50%); + background-size: calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2); +} + +.bg-pattern-diagonal { + @include pattern-base(); + background-image: repeating-linear-gradient(-45deg, var(--pattern-fill) 0 1px, transparent 0 50%); background-size: var(--pattern-size) var(--pattern-size); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-diagonal-2 { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(); background-image: repeating-linear-gradient(45deg, var(--pattern-fill) 0 1px, transparent 0 50%); - background-clip: padding-box; background-size: var(--pattern-size) var(--pattern-size); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-dots { - --pattern-color: var(--body-color); - --pattern-size: 5px; - --pattern-dot: 0.5px; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 20%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); - background-image: radial-gradient(circle, var(--pattern-fill) var(--pattern-dot), transparent var(--pattern-dot)), radial-gradient(circle, var(--pattern-fill) var(--pattern-dot), transparent var(--pattern-dot)); + @include pattern-base(20%); + --pattern-dot: max(1px, calc(var(--pattern-size) * 0.1)); + background-image: radial-gradient(circle, var(--pattern-fill) var(--pattern-dot), transparent calc(var(--pattern-dot) + 0.5px)), radial-gradient(circle, var(--pattern-fill) var(--pattern-dot), transparent calc(var(--pattern-dot) + 0.5px)); background-position: 0 0, - calc(var(--pattern-size) / 2) calc(var(--pattern-size) / 2); - background-clip: padding-box; - background-size: var(--pattern-size) var(--pattern-size); - border: var(--border-width) var(--border-style) var(--pattern-border); + calc(var(--pattern-size)) calc(var(--pattern-size)); + background-size: calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2); } .bg-pattern-rectangles { - --pattern-color: var(--body-color); - --pattern-fill: color-mix(in oklch, var(--pattern-color) 3%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-size: #{$pattern-size}; + @include pattern-base(3%); background-image: repeating-linear-gradient(45deg, var(--pattern-fill) 25%, transparent 25%, transparent 75%, var(--pattern-fill) 75%, var(--pattern-fill)), repeating-linear-gradient(45deg, var(--pattern-fill) 25%, transparent 25%, transparent 75%, var(--pattern-fill) 75%, var(--pattern-fill)); background-position: -1px -1px, calc(var(--pattern-size) - 1px) calc(var(--pattern-size) - 1px); - background-clip: padding-box; background-size: calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-lines { - --pattern-color: var(--body-color); - --pattern-fill: color-mix(in oklch, var(--pattern-color) 6%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-size: #{$pattern-size}; + @include pattern-base(6%); background-image: repeating-linear-gradient(0deg, var(--pattern-fill), var(--pattern-fill) 1px, transparent 1px, transparent); background-position: -1px -1px; - background-clip: padding-box; background-size: var(--pattern-size) var(--pattern-size); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-lines-vertical { - --pattern-color: var(--body-color); - --pattern-fill: color-mix(in oklch, var(--pattern-color) 6%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-size: #{$pattern-size}; + @include pattern-base(6%); background-image: repeating-linear-gradient(90deg, var(--pattern-fill), var(--pattern-fill) 1px, transparent 1px, transparent); background-position: -1px -1px; - background-clip: padding-box; background-size: var(--pattern-size) var(--pattern-size); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-grid { - --pattern-color: var(--body-color); - --pattern-fill: color-mix(in oklch, var(--pattern-color) 6%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-size: #{$pattern-size}; + @include pattern-base(6%); background-image: linear-gradient(to right, var(--pattern-fill) 1px, transparent 1px), linear-gradient(to bottom, var(--pattern-fill) 1px, transparent 1px); background-position: -1px -1px, -1px -1px; - background-clip: padding-box; background-size: calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-grid-diagonal { - --pattern-color: var(--body-color); - --pattern-fill: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-size: #{$pattern-size}; + @include pattern-base(); background-image: linear-gradient(45deg, transparent 49%, var(--pattern-fill) 49%, var(--pattern-fill) 51%, transparent 51%), linear-gradient(-45deg, transparent 49%, var(--pattern-fill) 49%, var(--pattern-fill) 51%, transparent 51%); background-position: center center; - background-clip: padding-box; background-size: calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-blueprint { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-line: color-mix(in oklch, var(--pattern-color) 6%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(6%); + --pattern-line: var(--pattern-fill); background-image: linear-gradient(var(--pattern-line) 2px, transparent 2px), linear-gradient(90deg, var(--pattern-line) 2px, transparent 2px), linear-gradient(var(--pattern-line) 1px, transparent 1px), linear-gradient(90deg, var(--pattern-line) 1px, transparent 1px); background-position: -3px -3px, -3px -3px, -2px -2px, -2px -2px; - background-clip: padding-box; background-size: calc(var(--pattern-size) * 10) calc(var(--pattern-size) * 10), calc(var(--pattern-size) * 10) calc(var(--pattern-size) * 10), calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2), calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-cross-dots { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(); background-image: radial-gradient(var(--pattern-fill) 1px, transparent 1px), radial-gradient(var(--pattern-fill) 1px, transparent 1px); background-position: 0 0, var(--pattern-size) var(--pattern-size); - background-clip: padding-box; background-size: calc(var(--pattern-size) * 2) calc(var(--pattern-size) * 2); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-circles { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 10%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(); background-image: radial-gradient(circle at center top, transparent 9%, var(--pattern-fill) 10%, var(--pattern-fill) 15%, transparent 16%), radial-gradient(circle at center bottom, transparent 9%, var(--pattern-fill) 10%, var(--pattern-fill) 15%, transparent 16%), radial-gradient(circle at right center, transparent 9%, var(--pattern-fill) 10%, var(--pattern-fill) 15%, transparent 16%), radial-gradient(circle at left center, transparent 9%, var(--pattern-fill) 10%, var(--pattern-fill) 15%, transparent 16%); background-position: 0 0; background-size: calc(var(--pattern-size) * 3) calc(var(--pattern-size) * 3); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-diagonal-stripes { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 5%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(5%); background-image: repeating-linear-gradient(45deg, transparent, transparent var(--pattern-size), var(--pattern-fill) var(--pattern-size), var(--pattern-fill) calc(2 * var(--pattern-size))); background-repeat: no-repeat; - background-clip: padding-box; - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-diagonal-stripes-2 { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 5%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(5%); background-image: repeating-linear-gradient(-45deg, transparent, transparent var(--pattern-size), var(--pattern-fill) var(--pattern-size), var(--pattern-fill) calc(2 * var(--pattern-size))); background-repeat: no-repeat; - background-clip: padding-box; - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-zigzag { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 5%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(5%); background: linear-gradient(135deg, var(--pattern-fill) 25%, transparent 25%) calc(-1 * var(--pattern-size)) 0, linear-gradient(225deg, var(--pattern-fill) 25%, transparent 25%) calc(-1 * var(--pattern-size)) 0, @@ -182,28 +130,17 @@ linear-gradient(45deg, var(--pattern-fill) 25%, transparent 25%); background-clip: padding-box; background-size: calc(2 * var(--pattern-size)) calc(2 * var(--pattern-size)); - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-vertical-stripes { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 5%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(5%); background-image: repeating-linear-gradient(90deg, transparent, transparent var(--pattern-size), var(--pattern-fill) var(--pattern-size), var(--pattern-fill) calc(2 * var(--pattern-size))); - background-clip: padding-box; - border: var(--border-width) var(--border-style) var(--pattern-border); } .bg-pattern-horizontal-stripes { - --pattern-color: var(--body-color); - --pattern-size: #{$pattern-size}; - --pattern-fill: color-mix(in oklch, var(--pattern-color) 5%, transparent); - --pattern-border: color-mix(in oklch, var(--pattern-color) 10%, transparent); + @include pattern-base(5%); background-image: repeating-linear-gradient(0deg, transparent, transparent var(--pattern-size), var(--pattern-fill) var(--pattern-size), var(--pattern-fill) calc(2 * var(--pattern-size))); background-position: -1px -1px; - background-clip: padding-box; - border: var(--border-width) var(--border-style) var(--pattern-border); } // Color variants @@ -226,3 +163,9 @@ $sizes: ( --pattern-size: #{$value}; } } + +@each $key, $value in $pattern-opacities { + .bg-pattern-opacity-#{$key} { + --pattern-opacity: #{$value}; + } +} diff --git a/docs/content/ui/utilities/background-patterns.mdx b/docs/content/ui/utilities/background-patterns.mdx index 74502de47..7268979a7 100644 --- a/docs/content/ui/utilities/background-patterns.mdx +++ b/docs/content/ui/utilities/background-patterns.mdx @@ -42,7 +42,7 @@ Here are the available pattern types: {patterns.map((pattern, i) => { return (
-
+
.bg-pattern-{ pattern }
) @@ -63,7 +63,7 @@ Combine any pattern with color modifiers using `.bg-pattern-{color}`. See the [f
-{colors.map((color) => (
.bg-pattern-{ color[0] }
))} +{colors.map((color) => (
.bg-pattern-{ color[0] }
))}
@@ -75,7 +75,7 @@ Combine any pattern with color modifiers using `.bg-pattern-{color}`. See the [f ## Transparent pattern utility -Use `.bg-pattern-transparent` when you need a checkerboard-style transparent background. This utility comes from the generic background utilities and can be combined with spacing and border classes. +Use `.bg-pattern-transparent` when you need a checkerboard-style transparent background. Combine it with spacing and border classes. You can change strength with `--tblr-pattern-opacity` (include the `%` unit). @@ -98,19 +98,19 @@ Look at the following examples to see how the pattern sizes work:
-
+
.bg-pattern-sm
-
+
.bg-pattern-md
-
+
.bg-pattern-lg
-
+
.bg-pattern-xl
@@ -122,6 +122,42 @@ Look at the following examples to see how the pattern sizes work:
+## Pattern opacity + +Use opacity utilities to control how strong the texture is: + +- `.bg-pattern-opacity-lighter` +- `.bg-pattern-opacity-light` +- `.bg-pattern-opacity-dark` +- `.bg-pattern-opacity-darker` + + +
+
+
+ .bg-pattern-opacity-lighter +
+
+
+ .bg-pattern-opacity-light +
+
+
+ .bg-pattern-opacity-dark +
+
+
+ .bg-pattern-opacity-darker +
+
+
+ +
+
+
+
+
+ ## Examples Look at the following examples to see how background patterns can be used in real layouts. diff --git a/preview/pages/patterns.astro b/preview/pages/patterns.astro index be59369a3..a356abde0 100644 --- a/preview/pages/patterns.astro +++ b/preview/pages/patterns.astro @@ -10,6 +10,7 @@ import DocsLink from '@ui/DocsLink.astro' const patternColors = Object.keys(site.colors) const patternSizes = ['sm', 'md', 'lg', 'xl'] as const +const patternOpacities = ['lighter', 'light', 'dark', 'darker'] as const const patterns = ['diagonal', 'diagonal-2', 'dots', 'rectangles', 'lines', 'lines-vertical', 'grid', 'grid-diagonal', 'blueprint', 'circles', 'diagonal-stripes', 'diagonal-stripes-2', 'zigzag', 'vertical-stripes', 'horizontal-stripes'] as const --- @@ -27,7 +28,7 @@ const patterns = ['diagonal', 'diagonal-2', 'dots', 'rectangles', 'lines', 'line { patterns.map((pattern) => (
- + .bg-pattern-{pattern}
)) @@ -45,7 +46,7 @@ const patterns = ['diagonal', 'diagonal-2', 'dots', 'rectangles', 'lines', 'line { patternColors.map((color) => (
- + .bg-pattern-{color}
)) @@ -63,7 +64,7 @@ const patterns = ['diagonal', 'diagonal-2', 'dots', 'rectangles', 'lines', 'line { patternSizes.map((size) => (
- + .bg-pattern-{size}
)) @@ -72,5 +73,63 @@ const patterns = ['diagonal', 'diagonal-2', 'dots', 'rectangles', 'lines', 'line +
+ + + Pattern opacity + Scale the pattern strength with lighter, light, dark, or darker. +
+ { + patternOpacities.map((opacity) => ( +
+ + .bg-pattern-opacity-{opacity} +
+ )) + } +
+
+
+
+
+ + + Usage + Combine pattern type, color, size, and opacity on real layouts. +
+
+ + .bg-pattern-transparent +
+
+ + .bg-pattern-grid.bg-pattern-primary.bg-pattern-lg.bg-pattern-opacity-light +
+
+ + .bg-pattern-diagonal-stripes-2.bg-pattern-azure.bg-pattern-opacity-dark +
+
+ + .bg-pattern-dots.bg-pattern-red.bg-pattern-sm.bg-pattern-opacity-darker +
+
+ + + Card with .bg-pattern-diagonal. + + +
+
+ + + Card with a primary grid and .bg-pattern-opacity-light. + + +
+
+
+
+
diff --git a/screenshots/pages/background-pattern-colors.astro b/screenshots/pages/background-pattern-colors.astro index f5b445ebe..febb30713 100644 --- a/screenshots/pages/background-pattern-colors.astro +++ b/screenshots/pages/background-pattern-colors.astro @@ -19,7 +19,7 @@ const patternColors = Object.keys(site.colors) { patternColors.map((color) => (
- + .bg-pattern-{color}
)) diff --git a/screenshots/pages/background-pattern-utilities.astro b/screenshots/pages/background-pattern-utilities.astro index 953d403e6..3b3d9b8f8 100644 --- a/screenshots/pages/background-pattern-utilities.astro +++ b/screenshots/pages/background-pattern-utilities.astro @@ -19,7 +19,7 @@ const patterns = ['diagonal', 'dots', 'rectangles', 'grid', 'blueprint', 'circle { patterns.map((pattern) => (
- + .bg-pattern-{pattern}
)) diff --git a/shared/ui/BackgroundPattern.astro b/shared/ui/BackgroundPattern.astro index 1d4c9ee7c..ac99c8a32 100644 --- a/shared/ui/BackgroundPattern.astro +++ b/shared/ui/BackgroundPattern.astro @@ -3,7 +3,7 @@ // combine with a theme color and/or size, e.g. . interface Props { - pattern: 'diagonal' | 'diagonal-2' | 'dots' | 'rectangles' | 'lines' | 'lines-vertical' | 'grid' | 'grid-diagonal' | 'blueprint' | 'cross-dots' | 'circles' | 'diagonal-stripes' | 'diagonal-stripes-2' | 'zigzag' | 'vertical-stripes' | 'horizontal-stripes' + pattern: 'diagonal' | 'diagonal-2' | 'dots' | 'rectangles' | 'lines' | 'lines-vertical' | 'grid' | 'grid-diagonal' | 'blueprint' | 'cross-dots' | 'circles' | 'diagonal-stripes' | 'diagonal-stripes-2' | 'zigzag' | 'vertical-stripes' | 'horizontal-stripes' | 'transparent' /** theme color the pattern ramps up to, e.g. 'primary' */ color?: string size?: 'sm' | 'md' | 'lg' | 'xl'