@omnisass/library 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/_configs.scss +68 -0
- package/index.scss +95 -0
- package/modules/utilities/converters/_convert-camel2kebab.scss +186 -0
- package/modules/utilities/converters/_convert-em2px.scss +239 -0
- package/modules/utilities/converters/_convert-hex2rgb.scss +97 -0
- package/modules/utilities/converters/_convert-hex2rgba.scss +124 -0
- package/modules/utilities/converters/_convert-kebab2camel.scss +232 -0
- package/modules/utilities/converters/_convert-kebab2snake.scss +118 -0
- package/modules/utilities/converters/_convert-px2em.scss +236 -0
- package/modules/utilities/converters/_convert-px2rem.scss +180 -0
- package/modules/utilities/converters/_convert-rem2px.scss +207 -0
- package/modules/utilities/converters/_convert-snake2kebab.scss +173 -0
- package/modules/utilities/getters/color/_get-color-brightness.scss +138 -0
- package/modules/utilities/getters/color/_get-color-darkest.scss +178 -0
- package/modules/utilities/getters/list/_get-list-item-end.scss +114 -0
- package/modules/utilities/getters/list/_get-list-item-start.scss +109 -0
- package/modules/utilities/getters/list/_get-list-item.scss +179 -0
- package/modules/utilities/getters/number/_get-number-from-percent.scss +139 -0
- package/modules/utilities/getters/number/_get-number-height-by-ratio.scss +199 -0
- package/modules/utilities/getters/number/_get-number-max.scss +168 -0
- package/modules/utilities/getters/number/_get-number-min.scss +162 -0
- package/modules/utilities/getters/number/_get-number-percentage-of.scss +149 -0
- package/modules/utilities/getters/number/_get-number-unit.scss +111 -0
- package/modules/utilities/getters/number/_get-number-width-by-ratio.scss +223 -0
- package/modules/utilities/helpers/color/_color-blend-steps.scss +210 -0
- package/modules/utilities/helpers/color/_color-blend.scss +183 -0
- package/modules/utilities/helpers/color/_color-hue-shift.scss +148 -0
- package/modules/utilities/helpers/color/_color-scale.scss +208 -0
- package/modules/utilities/helpers/color/_color-shade.scss +113 -0
- package/modules/utilities/helpers/color/_color-tint.scss +118 -0
- package/modules/utilities/helpers/color/_color-triad.scss +141 -0
- package/modules/utilities/helpers/list/_list-dedupe.scss +146 -0
- package/modules/utilities/helpers/list/_list-insert-at.scss +166 -0
- package/modules/utilities/helpers/list/_list-merge.scss +86 -0
- package/modules/utilities/helpers/list/_list-remove-at.scss +160 -0
- package/modules/utilities/helpers/list/_list-sum-numbers-safe.scss +175 -0
- package/modules/utilities/helpers/list/_list-sum-numbers.scss +128 -0
- package/modules/utilities/helpers/misc/_url-encode.configs.scss +64 -0
- package/modules/utilities/helpers/misc/_url-encode.scss +148 -0
- package/modules/utilities/helpers/number/_number-ceil-to.scss +111 -0
- package/modules/utilities/helpers/number/_number-clamp-max.scss +92 -0
- package/modules/utilities/helpers/number/_number-clamp-min.scss +100 -0
- package/modules/utilities/helpers/number/_number-clamp.scss +109 -0
- package/modules/utilities/helpers/number/_number-denormalize.scss +172 -0
- package/modules/utilities/helpers/number/_number-fibonacci.scss +235 -0
- package/modules/utilities/helpers/number/_number-floor-to.scss +114 -0
- package/modules/utilities/helpers/number/_number-format-with-separator.scss +122 -0
- package/modules/utilities/helpers/number/_number-normalize.scss +160 -0
- package/modules/utilities/helpers/number/_number-random-between-int.scss +84 -0
- package/modules/utilities/helpers/number/_number-random-between.scss +120 -0
- package/modules/utilities/helpers/number/_number-range.scss +268 -0
- package/modules/utilities/helpers/number/_number-round-to-nearest.scss +131 -0
- package/modules/utilities/helpers/number/_number-round-to.scss +118 -0
- package/modules/utilities/helpers/number/_number-strip-unit.scss +97 -0
- package/modules/utilities/helpers/string/_string-capitalize.scss +84 -0
- package/modules/utilities/helpers/string/_string-replace.scss +69 -0
- package/modules/utilities/helpers/string/_string-trim-end.scss +62 -0
- package/modules/utilities/helpers/string/_string-trim-start.scss +62 -0
- package/modules/utilities/helpers/string/_string-trim.scss +69 -0
- package/modules/utilities/loggers/_log-invalid-type.scss +151 -0
- package/modules/utilities/loggers/_log-invalid-value.scss +151 -0
- package/modules/utilities/setters/_index.scss +3 -0
- package/modules/utilities/validators/color/_is-color-light.scss +132 -0
- package/modules/utilities/validators/color/_is-color-list.scss +124 -0
- package/modules/utilities/validators/list/_is-list-contained.scss +65 -0
- package/modules/utilities/validators/misc/_is-time.scss +115 -0
- package/modules/utilities/validators/number/_is-int-even.scss +69 -0
- package/modules/utilities/validators/number/_is-int-odd.scss +70 -0
- package/modules/utilities/validators/number/_is-int.scss +124 -0
- package/modules/utilities/validators/number/_is-number-has-unit.scss +85 -0
- package/modules/utilities/validators/number/_is-number-negative.scss +76 -0
- package/modules/utilities/validators/number/_is-number-positive.scss +74 -0
- package/modules/utilities/validators/number/_is-number-unitless.scss +88 -0
- package/modules/utilities/validators/number/_is-number-zero.scss +75 -0
- package/modules/utilities/validators/string/_is-string-contained.scss +108 -0
- package/modules/utilities/validators/string/_is-string-empty.scss +56 -0
- package/modules/utilities/validators/string/_is-string-ending-with.scss +66 -0
- package/modules/utilities/validators/string/_is-string-starting-with.scss +66 -0
- package/modules/utilities/validators/type-of/_is-boolean.scss +92 -0
- package/modules/utilities/validators/type-of/_is-color.scss +96 -0
- package/modules/utilities/validators/type-of/_is-list.scss +105 -0
- package/modules/utilities/validators/type-of/_is-map.scss +105 -0
- package/modules/utilities/validators/type-of/_is-number.scss +103 -0
- package/modules/utilities/validators/type-of/_is-string.scss +110 -0
- package/modules/utilities/validators/type-of/_is-type.scss +77 -0
- package/package.json +54 -0
- package/package.scss +156 -0
- package/test.md +168 -0
- package/test.scss +405 -0
- package/test.sh +149 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
@use 'sass:math';
|
|
2
|
+
@use '../../loggers/log-invalid-type' as *;
|
|
3
|
+
@use '../../validators/type-of/is-number' as *;
|
|
4
|
+
|
|
5
|
+
/// Вычисляет ширину на основе высоты и соотношения сторон.
|
|
6
|
+
///
|
|
7
|
+
/// Функция рассчитывает ширину элемента по заданной высоте и
|
|
8
|
+
/// соотношению сторон (aspect ratio). Соотношение сторон
|
|
9
|
+
/// определяется как `ширина / высота`. Эта функция является
|
|
10
|
+
/// обратной к `get-number-height-by-ratio()` и используется в
|
|
11
|
+
/// тех же сценариях адаптивного веб-дизайна, когда известна
|
|
12
|
+
/// высота, но нужно вычислить соответствующую ширину для
|
|
13
|
+
/// сохранения пропорций.
|
|
14
|
+
///
|
|
15
|
+
/// Математическая формула:
|
|
16
|
+
/// - `width = height × ratio` (где `ratio = width / height`)
|
|
17
|
+
///
|
|
18
|
+
/// Свойства результата:
|
|
19
|
+
/// - При `ratio = 1` (квадрат) → ширина равна высоте
|
|
20
|
+
/// - При `ratio > 1` (альбомная ориентация) → ширина больше
|
|
21
|
+
/// высоты
|
|
22
|
+
/// - При `ratio < 1` (портретная ориентация) → ширина меньше
|
|
23
|
+
/// высоты
|
|
24
|
+
/// - Результат имеет те же единицы измерения, что и `$height`
|
|
25
|
+
/// - Функция сохраняет пропорции исходного соотношения сторон
|
|
26
|
+
///
|
|
27
|
+
/// Важные особенности функции:
|
|
28
|
+
/// - Вычисляет ширину по высоте и соотношению сторон
|
|
29
|
+
/// - Использует умножение вместо деления (более эффективно)
|
|
30
|
+
/// - Сохраняет единицы измерения высоты (px, rem, em, %, и т.д.)
|
|
31
|
+
/// - Поддерживает дробные значения соотношения сторон
|
|
32
|
+
/// - Идеально подходит для вертикально-ориентированных
|
|
33
|
+
/// интерфейсов
|
|
34
|
+
/// - Является парной функцией к `get-number-height-by-ratio()`
|
|
35
|
+
///
|
|
36
|
+
/// > Вычисление ширины по соотношению сторон особенно полезно
|
|
37
|
+
/// > в мобильных интерфейсах и вертикальных макетах, где высота
|
|
38
|
+
/// > может быть фиксированной или известной заранее. Этот подход
|
|
39
|
+
/// > позволяет создавать адаптивные элементы, которые сохраняют
|
|
40
|
+
/// > пропорции независимо от ориентации устройства.
|
|
41
|
+
/// >
|
|
42
|
+
/// > Пример: для отображения изображения 4:3 с высотой 300px,
|
|
43
|
+
/// > ширина будет вычислена как 300 × (4/3) = 400px.
|
|
44
|
+
/// ---
|
|
45
|
+
/// @name get-number-width-by-ratio
|
|
46
|
+
/// @group utilities-getters
|
|
47
|
+
/// @since 2025.12.27
|
|
48
|
+
/// @access public
|
|
49
|
+
/// @author Murad Rustamov (therteenten)
|
|
50
|
+
/// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
|
|
51
|
+
/// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
|
|
52
|
+
/// @link https://sass-lang.com/documentation/values/numbers См. также: Официальная документация Sass - Тип данных "Числа"
|
|
53
|
+
/// @link https://sass-lang.com/documentation/modules/math См. также: Официальная документация Sass - Модуль math
|
|
54
|
+
/// @link https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio См. также: MDN Web Docs - CSS свойство aspect-ratio
|
|
55
|
+
/// @link https://css-tricks.com/aspect-ratio-boxes/ См. также: CSS-Tricks - Блоки с фиксированным соотношением сторон
|
|
56
|
+
/// @link https://www.w3schools.com/howto/howto_css_aspect_ratio.asp См. также: W3Schools - Как создавать блоки с фиксированным соотношением сторон
|
|
57
|
+
/// @example scss - Стандартные соотношения сторон видео
|
|
58
|
+
/// @debug get-number-width-by-ratio(450px, math.div(16, 9)); // 800px
|
|
59
|
+
/// @debug get-number-width-by-ratio(450px, 1.7777777778); // 800.00000001px
|
|
60
|
+
/// @debug get-number-width-by-ratio(600px, math.div(4, 3)); // 800px
|
|
61
|
+
/// @debug get-number-width-by-ratio(600px, 1.3333333333); // 799.99999998px
|
|
62
|
+
/// @debug get-number-width-by-ratio(342.8571428571px, math.div(21, 9)); // 799.9999999999px
|
|
63
|
+
/// @debug get-number-width-by-ratio(342.8571428571px, 2.3333333333); // 799.9999999884714px
|
|
64
|
+
/// @example scss - Квадратные и прямоугольные элементы
|
|
65
|
+
/// @debug get-number-width-by-ratio(400px, 1); // 400px (квадрат)
|
|
66
|
+
/// @debug get-number-width-by-ratio(300px, 2); // 600px (горизонтальный прямоугольник 2:1)
|
|
67
|
+
/// @debug get-number-width-by-ratio(1200px, 0.5); // 600px (вертикальный прямоугольник 1:2)
|
|
68
|
+
/// @debug get-number-width-by-ratio(200px, math.div(3, 2)); // 300px (3:2)
|
|
69
|
+
/// @debug get-number-width-by-ratio(450px, math.div(2, 3)); // 300px (2:3)
|
|
70
|
+
/// @example scss - Разные единицы измерения
|
|
71
|
+
/// @debug get-number-width-by-ratio(56.25%, math.div(16, 9)); // 100%
|
|
72
|
+
/// @debug get-number-width-by-ratio(28.125rem, math.div(16, 9)); // 50rem
|
|
73
|
+
/// @debug get-number-width-by-ratio(45vw, math.div(16, 9)); // 80vw
|
|
74
|
+
/// @debug get-number-width-by-ratio(675px, math.div(16, 9)); // 1200px
|
|
75
|
+
/// @debug get-number-width-by-ratio(48em, math.div(4, 3)); // 64em
|
|
76
|
+
/// @example scss - Дробные значения высоты
|
|
77
|
+
/// @debug get-number-width-by-ratio(422.15625px, math.div(16, 9)); // 750.5px
|
|
78
|
+
/// @debug get-number-width-by-ratio(683.1666666667px, 1.5); // 1024.75000000005px
|
|
79
|
+
/// @debug get-number-width-by-ratio(205rem, math.div(5, 4)); // 256.25rem
|
|
80
|
+
/// @debug get-number-width-by-ratio(61.7435117429%, 1.618); // 99.9010020000122% (золотое сечение)
|
|
81
|
+
/// @example scss - Популярные соотношения сторон (обратные вычисления)
|
|
82
|
+
/// // 1:1 - Квадрат, Instagram фото
|
|
83
|
+
/// @debug get-number-width-by-ratio(500px, 1); // 500px
|
|
84
|
+
///
|
|
85
|
+
/// // 4:3 - Стандартный монитор, некоторые планшеты
|
|
86
|
+
/// @debug get-number-width-by-ratio(768px, math.div(4, 3)); // 1024px
|
|
87
|
+
///
|
|
88
|
+
/// // 16:9 - Современное видео, Full HD
|
|
89
|
+
/// @debug get-number-width-by-ratio(1080px, math.div(16, 9)); // 1920px
|
|
90
|
+
///
|
|
91
|
+
/// // 21:9 - Ультраширокий монитор, кинематографичный формат
|
|
92
|
+
/// @debug get-number-width-by-ratio(1097.1428571429px, math.div(21, 9)); // 2560.0000000001005px
|
|
93
|
+
///
|
|
94
|
+
/// // 3:2 - Некоторые фотоаппараты, MacBook
|
|
95
|
+
/// @debug get-number-width-by-ratio(1200px, math.div(3, 2)); // 1800px
|
|
96
|
+
///
|
|
97
|
+
/// // 1.618:1 - Золотое сечение
|
|
98
|
+
/// @debug get-number-width-by-ratio(618.0463572312px, 1.618); // 999.9990060000816px
|
|
99
|
+
/// @example scss - Для вертикальных адаптивных контейнеров
|
|
100
|
+
/// .vertical-video-container {
|
|
101
|
+
/// height: 100vh;
|
|
102
|
+
/// width: get-number-width-by-ratio(100vh, math.div(9, 16));
|
|
103
|
+
/// }
|
|
104
|
+
///
|
|
105
|
+
/// .portrait-image {
|
|
106
|
+
/// height: 500px;
|
|
107
|
+
/// width: get-number-width-by-ratio(500px, math.div(3, 4));
|
|
108
|
+
/// }
|
|
109
|
+
///
|
|
110
|
+
/// .mobile-card {
|
|
111
|
+
/// height: 200px;
|
|
112
|
+
/// width: get-number-width-by-ratio(200px, math.div(4, 5));
|
|
113
|
+
/// }
|
|
114
|
+
/// @example css - Результат
|
|
115
|
+
/// .vertical-video-container {
|
|
116
|
+
/// height: 100vh;
|
|
117
|
+
/// width: 56.25vh;
|
|
118
|
+
/// }
|
|
119
|
+
///
|
|
120
|
+
/// .portrait-image {
|
|
121
|
+
/// height: 500px;
|
|
122
|
+
/// width: 375px;
|
|
123
|
+
/// }
|
|
124
|
+
///
|
|
125
|
+
/// .mobile-card {
|
|
126
|
+
/// height: 200px;
|
|
127
|
+
/// width: 160px;
|
|
128
|
+
/// }
|
|
129
|
+
/// @example scss - Динамические вычисления для известной высоты
|
|
130
|
+
/// $container-height: 675px;
|
|
131
|
+
/// $aspect-ratio: math.div(16, 9);
|
|
132
|
+
/// @debug get-number-width-by-ratio($container-height, $aspect-ratio); // 1200px
|
|
133
|
+
///
|
|
134
|
+
/// $mobile-height: 210.9375px;
|
|
135
|
+
/// @debug get-number-width-by-ratio($mobile-height, $aspect-ratio); // 375px
|
|
136
|
+
/// @example scss - Проверка граничных значений
|
|
137
|
+
/// @debug get-number-width-by-ratio(0px, math.div(16, 9)); // 0px
|
|
138
|
+
/// @debug get-number-width-by-ratio(1000px, 0); // 0px (соотношение 0 означает нулевую ширину)
|
|
139
|
+
/// // @debug get-number-width-by-ratio(1000px, math.infinity()); // infinity (теоретически), а так Error
|
|
140
|
+
/// @example scss - Очень большие и малые соотношения
|
|
141
|
+
/// @debug get-number-width-by-ratio(100px, 10); // 1000px (очень широкий)
|
|
142
|
+
/// @debug get-number-width-by-ratio(10000px, 0.1); // 1000px (очень узкий)
|
|
143
|
+
/// @debug get-number-width-by-ratio(5px, 100); // 500px
|
|
144
|
+
/// @debug get-number-width-by-ratio(50000px, 0.01); // 500px
|
|
145
|
+
/// @param {Number} $height - Высота элемента. Может быть
|
|
146
|
+
/// любым числом с единицами измерения (`px`, `rem`, `em`,
|
|
147
|
+
/// `%`, `vh`, и т.д.)
|
|
148
|
+
/// или без них.
|
|
149
|
+
/// @param {Number} $ratio - Соотношение сторон, вычисляемое
|
|
150
|
+
/// как `ширина / высота`. Например:
|
|
151
|
+
/// - 1.7777777778 для 16:9
|
|
152
|
+
/// - 1.3333333333 для 4:3
|
|
153
|
+
/// - 1 для квадрата
|
|
154
|
+
/// - 0.75 для портретного формата 3:4
|
|
155
|
+
/// @return {Number} - Ширина элемента, рассчитанная по формуле
|
|
156
|
+
/// `width = height × ratio`. Сохраняет единицы измерения
|
|
157
|
+
/// параметра `$height`.
|
|
158
|
+
@function get-number-width-by-ratio($height, $ratio) {
|
|
159
|
+
|
|
160
|
+
@if not is-number($height) {
|
|
161
|
+
|
|
162
|
+
// Валидация первого параметра: высота.
|
|
163
|
+
// Функция ожидает числовое значение, которое может содержать
|
|
164
|
+
// единицы измерения (px, rem, em, %, и т.д.).
|
|
165
|
+
//
|
|
166
|
+
// Если $height не является числом (например, строка, булево
|
|
167
|
+
// значение), вызываем стандартизированную функцию
|
|
168
|
+
// логирования ошибок.
|
|
169
|
+
@return log-invalid-type(
|
|
170
|
+
'get-number-width-by-ratio',
|
|
171
|
+
$height,
|
|
172
|
+
'$height',
|
|
173
|
+
'number'
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@else if not is-number($ratio) {
|
|
179
|
+
|
|
180
|
+
// Валидация второго параметра: соотношение сторон.
|
|
181
|
+
// Соотношение должно быть числом (чаще всего безразмерным).
|
|
182
|
+
//
|
|
183
|
+
// Проверка выполняется только если $height прошел валидацию.
|
|
184
|
+
// Это последовательный подход fail-fast (быстрая остановка
|
|
185
|
+
// при ошибке).
|
|
186
|
+
@return log-invalid-type(
|
|
187
|
+
'get-number-width-by-ratio',
|
|
188
|
+
$ratio,
|
|
189
|
+
'$ratio',
|
|
190
|
+
'number'
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@else {
|
|
196
|
+
|
|
197
|
+
// Оба параметра валидны - выполняем вычисление.
|
|
198
|
+
//
|
|
199
|
+
// Формула: ширина = высота × соотношение.
|
|
200
|
+
//
|
|
201
|
+
// Важные аспекты:
|
|
202
|
+
// 1. Умножение $height (с единицами) на $ratio (безразмерное)
|
|
203
|
+
// сохраняет единицы измерения из $height
|
|
204
|
+
// 2. Если $ratio также имеет единицы, Sass попытается их
|
|
205
|
+
// перемножить, что может привести к неожиданным результатам
|
|
206
|
+
// 3. Рекомендуется передавать $ratio как безразмерное число
|
|
207
|
+
@return $height * $ratio;
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// @name get-width-by-ratio
|
|
214
|
+
/// @alias get-number-width-by-ratio
|
|
215
|
+
/// @group utilities-aliases
|
|
216
|
+
/// @since 2025.12.27
|
|
217
|
+
/// @access public
|
|
218
|
+
/// @author Murad Rustamov (therteenten)
|
|
219
|
+
/// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
|
|
220
|
+
/// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
|
|
221
|
+
@function get-width-by-ratio($height, $ratio) {
|
|
222
|
+
@return get-number-width-by-ratio($height, $ratio);
|
|
223
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
@use 'sass:math';
|
|
2
|
+
@use 'sass:list';
|
|
3
|
+
@use 'sass:color';
|
|
4
|
+
@use '../../loggers/log-invalid-type' as *;
|
|
5
|
+
@use '../../validators/type-of/is-color' as *;
|
|
6
|
+
@use '../../validators/type-of/is-number' as *;
|
|
7
|
+
|
|
8
|
+
/// Создает последовательность равномерно распределенных
|
|
9
|
+
/// цветов между двумя точками.
|
|
10
|
+
///
|
|
11
|
+
/// Функция `color-blend-steps()` генерирует список
|
|
12
|
+
/// промежуточных цветов, равномерно распределенных между
|
|
13
|
+
/// начальным и конечным цветами.
|
|
14
|
+
///
|
|
15
|
+
/// Каждый цвет в последовательности представляет собой
|
|
16
|
+
/// линейную интерполяцию между `$color-start` и `$color-end` с
|
|
17
|
+
/// определенным процентом смешивания. Полезно для создания
|
|
18
|
+
/// цветовых градиентов с дискретными остановками, генерации
|
|
19
|
+
/// палитр или построения систем цветовых переходов с
|
|
20
|
+
/// контролируемым количеством шагов.
|
|
21
|
+
///
|
|
22
|
+
/// > Все шаги равномерно распределены математически, но визуально
|
|
23
|
+
/// > могут восприниматься неравномерно в зависимости от цветового
|
|
24
|
+
/// > пространства.
|
|
25
|
+
/// ---
|
|
26
|
+
/// @name color-blend-steps
|
|
27
|
+
/// @group utilities-helpers
|
|
28
|
+
/// @since 2025.12.27
|
|
29
|
+
/// @access public
|
|
30
|
+
/// @author Murad Rustamov (therteenten)
|
|
31
|
+
/// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
|
|
32
|
+
/// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
|
|
33
|
+
/// @link https://sass-lang.com/documentation/modules/color#mix См. также: Sass - Функция color.mix()
|
|
34
|
+
/// @link https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient См. также: MDN - Линейные градиенты
|
|
35
|
+
/// @link https://www.w3.org/TR/css-color-5/#color-mix См. также: W3C - Спецификация color-mix
|
|
36
|
+
/// @link https://css-tricks.com/striped-css-gradients/ См. также: CSS-Tricks - Полосатые CSS-градиенты
|
|
37
|
+
/// @example scss - Использование для CSS-переменных
|
|
38
|
+
/// @use 'sass:list';
|
|
39
|
+
///
|
|
40
|
+
/// :root {
|
|
41
|
+
///
|
|
42
|
+
/// $transition: color-blend-steps(#3498db, #2c3e50, 4);
|
|
43
|
+
///
|
|
44
|
+
/// @for $i from 1 through list.length($transition) {
|
|
45
|
+
/// --color-step-#{$i}: #{list.nth($transition, $i)};
|
|
46
|
+
/// }
|
|
47
|
+
///
|
|
48
|
+
/// }
|
|
49
|
+
/// @example css - Результат
|
|
50
|
+
/// :root {
|
|
51
|
+
/// --color-step-1: #3498db;
|
|
52
|
+
/// --color-step-2: rgb(50, 129.5, 184.25);
|
|
53
|
+
/// --color-step-3: rgb(48, 107, 149.5);
|
|
54
|
+
/// --color-step-4: rgb(46, 84.5, 114.75);
|
|
55
|
+
/// --color-step-5: #2c3e50;
|
|
56
|
+
/// }
|
|
57
|
+
/// @example scss - Создание плавного hover-эффекта с шагами
|
|
58
|
+
/// @use 'sass:list';
|
|
59
|
+
///
|
|
60
|
+
/// .progress-bar {
|
|
61
|
+
/// $colors: color-blend-steps(#2ecc71, #e74c3c, 5);
|
|
62
|
+
///
|
|
63
|
+
/// @for $i from 1 through list.length($colors) {
|
|
64
|
+
/// &--step-#{$i} {
|
|
65
|
+
/// background-color: list.nth($colors, $i);
|
|
66
|
+
/// }
|
|
67
|
+
/// }
|
|
68
|
+
///
|
|
69
|
+
/// }
|
|
70
|
+
/// @example css - Результат
|
|
71
|
+
/// .progress-bar--step-1 {
|
|
72
|
+
/// background-color: #2ecc71;
|
|
73
|
+
/// }
|
|
74
|
+
/// .progress-bar--step-2 {
|
|
75
|
+
/// background-color: rgb(83, 178.4, 102.4);
|
|
76
|
+
/// }
|
|
77
|
+
/// .progress-bar--step-3 {
|
|
78
|
+
/// background-color: rgb(120, 152.8, 91.8);
|
|
79
|
+
/// }
|
|
80
|
+
/// .progress-bar--step-4 {
|
|
81
|
+
/// background-color: rgb(157, 127.2, 81.2);
|
|
82
|
+
/// }
|
|
83
|
+
/// .progress-bar--step-5 {
|
|
84
|
+
/// background-color: rgb(194, 101.6, 70.6);
|
|
85
|
+
/// }
|
|
86
|
+
/// .progress-bar--step-6 {
|
|
87
|
+
/// background-color: #e74c3c;
|
|
88
|
+
/// }
|
|
89
|
+
/// @example scss - Генерация градиента с дискретными остановками
|
|
90
|
+
/// @use 'sass:list';
|
|
91
|
+
///
|
|
92
|
+
/// .gradient-stripes {
|
|
93
|
+
/// background: linear-gradient(
|
|
94
|
+
/// to right,
|
|
95
|
+
/// #{list.nth(color-blend-steps(#ff0000, #00ff00, 5), 1)},
|
|
96
|
+
/// #{list.nth(color-blend-steps(#ff0000, #00ff00, 5), 3)},
|
|
97
|
+
/// #{list.nth(color-blend-steps(#ff0000, #00ff00, 5), 5)},
|
|
98
|
+
/// #{list.nth(color-blend-steps(#ff0000, #00ff00, 5), 6)},
|
|
99
|
+
/// );
|
|
100
|
+
/// }
|
|
101
|
+
/// @example css - Результат
|
|
102
|
+
/// gradient-stripes {
|
|
103
|
+
/// background: linear-gradient(to right, red, #996600, #33cc00, lime);
|
|
104
|
+
/// }
|
|
105
|
+
/// @param {Color} $color-start - Начальный цвет последовательности.
|
|
106
|
+
/// Может быть в любом формате, поддерживаемом Sass (HEX, RGB,
|
|
107
|
+
/// HSL и т.д.).
|
|
108
|
+
/// @param {Color} $color-end - Конечный цвет последовательности.
|
|
109
|
+
/// Должен быть совместим по цветовому пространству с `$color-start`.
|
|
110
|
+
/// @param {Number} $steps [5] - Количество промежуточных шагов
|
|
111
|
+
/// между цветами. Определяет, сколько цветов будет сгенерировано
|
|
112
|
+
/// между начальным и конечным. Фактическое количество цветов в
|
|
113
|
+
/// результате = `$steps + 2`. Минимальное значение - `0` (вернет
|
|
114
|
+
/// только начальный и конечный цвета).
|
|
115
|
+
/// @return {List} - Упорядоченный список (list) цветов, где:
|
|
116
|
+
/// - Первый элемент: чистый `$color-start` (0% смешивания)
|
|
117
|
+
/// - Последний элемент: чистый `$color-end` (100% смешивания)
|
|
118
|
+
/// - Промежуточные элементы: равномерно распределенные смеси
|
|
119
|
+
/// - Всего элементов: `$steps + 2`
|
|
120
|
+
@function color-blend-steps($color-start, $color-end, $steps: 5) {
|
|
121
|
+
|
|
122
|
+
// Инициализация списка для хранения промежуточных цветов.
|
|
123
|
+
// Результатом функции будет список (массив) цветов,
|
|
124
|
+
// представляющих градиентный переход от начального цвета
|
|
125
|
+
// к конечному.
|
|
126
|
+
$-colors: ();
|
|
127
|
+
|
|
128
|
+
// Проверка типа первого параметра: ожидается начальный цвет.
|
|
129
|
+
// Функция is-color() проверяет, является ли $color-start
|
|
130
|
+
// валидным цветом CSS.
|
|
131
|
+
@if not is-color($color-start) {
|
|
132
|
+
|
|
133
|
+
// Если $color-start не является цветом, возвращаем ошибку через
|
|
134
|
+
// стандартную функцию логирования. Это предотвращает
|
|
135
|
+
// некорректные вычисления с нецветовыми данными.
|
|
136
|
+
@return log-invalid-type(
|
|
137
|
+
'color-blend-steps',
|
|
138
|
+
$color-start,
|
|
139
|
+
'$color-start',
|
|
140
|
+
'color'
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Проверка типа второго параметра: ожидается конечный цвет.
|
|
146
|
+
// Проверка выполняется только если $color-start прошел валидацию.
|
|
147
|
+
@else if not is-color($color-end) {
|
|
148
|
+
|
|
149
|
+
// Если $color-end не является цветом, возвращаем ошибку.
|
|
150
|
+
@return log-invalid-type(
|
|
151
|
+
'color-blend-steps',
|
|
152
|
+
$color-end,
|
|
153
|
+
'$color-end',
|
|
154
|
+
'color'
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Проверка типа третьего параметра: ожидается количество шагов.
|
|
160
|
+
// $steps определяет, сколько промежуточных цветов будет сгенерировано
|
|
161
|
+
// между начальным и конечным цветом.
|
|
162
|
+
@else if not is-number($steps) {
|
|
163
|
+
|
|
164
|
+
// Если $steps не является числом, возвращаем ошибку.
|
|
165
|
+
@return log-invalid-type(
|
|
166
|
+
'color-blend-steps',
|
|
167
|
+
$steps,
|
|
168
|
+
'$steps',
|
|
169
|
+
'number'
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Все параметры прошли валидацию - выполняем генерацию цветов.
|
|
175
|
+
@else {
|
|
176
|
+
|
|
177
|
+
// Цикл генерации промежуточных цветов.
|
|
178
|
+
// Переменная $i принимает значения от 0 до $steps включительно.
|
|
179
|
+
// Это создает $steps + 1 цвет в итоговом списке
|
|
180
|
+
// (включая начальный и конечный цвета).
|
|
181
|
+
@for $i from 0 through $steps {
|
|
182
|
+
|
|
183
|
+
// Вычисление процентного соотношения для текущего шага.
|
|
184
|
+
// Формула: (текущий шаг) × (100% / общее количество шагов)
|
|
185
|
+
// Пример для 5 шагов: шаги будут на 0%, 20%, 40%, 60%, 80%, 100%
|
|
186
|
+
$-percentage: $i * math.div(100, $steps);
|
|
187
|
+
|
|
188
|
+
// Создание промежуточного цвета с помощью функции color.mix()
|
|
189
|
+
// color.mix() смешивает два цвета в указанной пропорции.
|
|
190
|
+
// Параметры:
|
|
191
|
+
// - $color-end: первый цвет для смешивания
|
|
192
|
+
// - $color-start: второй цвет для смешивания
|
|
193
|
+
// - $-percentage * 1%: процентное соотношение
|
|
194
|
+
// (сколько процентов $color-start в смеси)
|
|
195
|
+
//
|
|
196
|
+
// Примечание: порядок параметров в color.mix() важен:
|
|
197
|
+
// - При $-percentage = 0% → 100% $color-end, 0% $color-start
|
|
198
|
+
// - При $-percentage = 100% → 0% $color-end, 100% $color-start
|
|
199
|
+
$-colors: list.append($-colors, color.mix($color-end, $color-start, $-percentage * 1%));
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Возвращаем список сгенерированных цветов.
|
|
204
|
+
// Список содержит $steps + 1 элементов, равномерно распределенных
|
|
205
|
+
// между начальным и конечным цветом.
|
|
206
|
+
@return $-colors;
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
@use 'sass:color';
|
|
2
|
+
@use '../../loggers/log-invalid-type' as *;
|
|
3
|
+
@use '../../validators/type-of/is-color' as *;
|
|
4
|
+
@use '../../validators/type-of/is-number' as *;
|
|
5
|
+
|
|
6
|
+
/// Линейная интерполяция (смешивание) между двумя цветами.
|
|
7
|
+
///
|
|
8
|
+
/// Функция `color-blend()` создает промежуточный цвет между
|
|
9
|
+
/// двумя заданными точками, используя линейную интерполяцию.
|
|
10
|
+
///
|
|
11
|
+
/// Это упрощенная обертка над встроенной функцией
|
|
12
|
+
/// `color.mix()` с автоматическим преобразованием процента.
|
|
13
|
+
/// Полезно для создания плавных переходов, градиентов,
|
|
14
|
+
/// оттенков или любого промежуточного состояния между двумя
|
|
15
|
+
/// цветами.
|
|
16
|
+
///
|
|
17
|
+
/// > Функция автоматически добавляет единицы % к
|
|
18
|
+
/// > параметру `$percentage`.
|
|
19
|
+
///
|
|
20
|
+
/// > Для сложных градиентов или смешивания в специфических
|
|
21
|
+
/// > пространствах используйте встроенную функцию
|
|
22
|
+
/// > `color.mix()` напрямую.
|
|
23
|
+
///
|
|
24
|
+
/// > Результат зависит от цветового пространства смешивания
|
|
25
|
+
/// > по умолчанию. Для контроля пространства используйте
|
|
26
|
+
/// > `color.mix()` с параметром `$space`.
|
|
27
|
+
/// ---
|
|
28
|
+
/// @name color-blend
|
|
29
|
+
/// @group utilities-helpers
|
|
30
|
+
/// @since 2025.12.27
|
|
31
|
+
/// @access public
|
|
32
|
+
/// @author Murad Rustamov (therteenten)
|
|
33
|
+
/// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
|
|
34
|
+
/// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
|
|
35
|
+
/// @link https://sass-lang.com/documentation/modules/color#mix См. также: Sass - Функция color.mix()
|
|
36
|
+
/// @link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix См. также: MDN - CSS функция color-mix()
|
|
37
|
+
/// @link https://www.w3.org/TR/css-color-5/#color-mix См. также: W3C - Спецификация color-mix
|
|
38
|
+
/// @link https://css-tricks.com/color-mix-function/ См. также: CSS-Tricks - Функция color-mix()
|
|
39
|
+
/// @example scss - Создание промежуточного оттенка
|
|
40
|
+
/// $mid-color: color-blend(#ff0000, #0000ff, 50);
|
|
41
|
+
///
|
|
42
|
+
/// // Результат: #800080 (фиолетовый)
|
|
43
|
+
/// .element {
|
|
44
|
+
/// color: $mid-color;
|
|
45
|
+
/// }
|
|
46
|
+
/// @example css - Результат
|
|
47
|
+
/// .element {
|
|
48
|
+
/// color: rgb(127.5, 0, 127.5);
|
|
49
|
+
/// }
|
|
50
|
+
/// @example scss - Плавный hover-эффект
|
|
51
|
+
/// .button {
|
|
52
|
+
/// background-color: #3498db;
|
|
53
|
+
///
|
|
54
|
+
/// &:hover {
|
|
55
|
+
/// // Плавное затемнение при наведении
|
|
56
|
+
/// background-color: color-blend(#3498db, #2c3e50, 70);
|
|
57
|
+
/// }
|
|
58
|
+
///
|
|
59
|
+
/// }
|
|
60
|
+
/// @example css - Результат
|
|
61
|
+
/// .button {
|
|
62
|
+
/// background-color: #3498db;
|
|
63
|
+
/// }
|
|
64
|
+
///
|
|
65
|
+
/// .button:hover {
|
|
66
|
+
/// background-color: rgb(46.4, 89, 121.7);
|
|
67
|
+
/// }
|
|
68
|
+
/// @example scss - Создание градиента с несколькими остановками
|
|
69
|
+
/// .gradient-box {
|
|
70
|
+
///
|
|
71
|
+
/// background: linear-gradient(
|
|
72
|
+
/// to right,
|
|
73
|
+
/// color-blend(#ff0000, #00ff00, 0),
|
|
74
|
+
/// color-blend(#ff0000, #00ff00, 25),
|
|
75
|
+
/// color-blend(#ff0000, #00ff00, 50),
|
|
76
|
+
/// color-blend(#ff0000, #00ff00, 75),
|
|
77
|
+
/// color-blend(#ff0000, #00ff00, 100)
|
|
78
|
+
/// );
|
|
79
|
+
///
|
|
80
|
+
/// }
|
|
81
|
+
/// @example css - Результат
|
|
82
|
+
/// .gradient-box {
|
|
83
|
+
/// background: linear-gradient(to right, red, rgb(191.25, 63.75, 0), rgb(127.5, 127.5, 0), rgb(63.75, 191.25, 0), lime);
|
|
84
|
+
/// }
|
|
85
|
+
/// @example scss - Осветление и затемнение через смешивание
|
|
86
|
+
/// // Лучше использовать функции color-shade и color-tint
|
|
87
|
+
/// // из набора OmniSass.
|
|
88
|
+
///
|
|
89
|
+
/// $base-color: #9b59b6;
|
|
90
|
+
/// $lightened: color-blend($base-color, white, 30); // Осветление на 30%
|
|
91
|
+
/// $darkened: color-blend($base-color, black, 30); // Затемнение на 30%
|
|
92
|
+
/// @see color-shade
|
|
93
|
+
/// @see color-tint
|
|
94
|
+
/// @param {Color} $color-from - Исходный (начальный) цвет. Может
|
|
95
|
+
/// быть в любом формате, поддерживаемом Sass (HEX, RGB,
|
|
96
|
+
/// HSL и т.д.).
|
|
97
|
+
/// @param {Color} $color-to - Целевой (конечный) цвет. Автоматически
|
|
98
|
+
/// приводится к тому же цветовому пространству, что и
|
|
99
|
+
/// `$color-from`.
|
|
100
|
+
/// @param {Number} $percentage - Процент смешивания от
|
|
101
|
+
/// `$color-from` к `$color-to` (0-100). Значение автоматически
|
|
102
|
+
/// конвертируется в проценты с помощью умножения на 1%.
|
|
103
|
+
/// - 0: возвращает чистый цвет `$color-from`
|
|
104
|
+
/// - 100: возвращает чистый цвет `$color-to`
|
|
105
|
+
/// - 50: возвращает ровную смесь `50/50`
|
|
106
|
+
/// @return {Color} - Промежуточный цвет, полученный линейной
|
|
107
|
+
/// интерполяцией между `$color-from` и `$color-to` в указанной пропорции.
|
|
108
|
+
/// Использует цветовое пространство по умолчанию для
|
|
109
|
+
/// смешивания (обычно sRGB).
|
|
110
|
+
@function color-blend($color-from, $color-to, $percentage) {
|
|
111
|
+
|
|
112
|
+
// Проверка типа первого параметра: ожидается начальный цвет.
|
|
113
|
+
// Функция is-color() проверяет, является ли $color-from
|
|
114
|
+
// валидным цветом CSS.
|
|
115
|
+
@if not is-color($color-from) {
|
|
116
|
+
|
|
117
|
+
// Если $color-from не является цветом, возвращаем ошибку через
|
|
118
|
+
// стандартную функцию логирования. Это предотвращает
|
|
119
|
+
// некорректные вычисления с нецветовыми данными.
|
|
120
|
+
@return log-invalid-type(
|
|
121
|
+
'color-blend',
|
|
122
|
+
$color-from,
|
|
123
|
+
'$color-from',
|
|
124
|
+
'color'
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Проверка типа второго параметра: ожидается конечный цвет.
|
|
130
|
+
// Проверка выполняется только если $color-from прошел валидацию.
|
|
131
|
+
@else if not is-color($color-to) {
|
|
132
|
+
|
|
133
|
+
// Если $color-to не является цветом, возвращаем ошибку.
|
|
134
|
+
@return log-invalid-type(
|
|
135
|
+
'color-blend',
|
|
136
|
+
$color-to,
|
|
137
|
+
'$color-to',
|
|
138
|
+
'color'
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Проверка типа третьего параметра: ожидается процент смешивания.
|
|
144
|
+
// $percentage определяет, сколько процентов начального цвета
|
|
145
|
+
// будет в итоговой смеси (от 0 до 100).
|
|
146
|
+
@else if not is-number($percentage) {
|
|
147
|
+
|
|
148
|
+
// Если $percentage не является числом, возвращаем ошибку.
|
|
149
|
+
@return log-invalid-type(
|
|
150
|
+
'color-blend',
|
|
151
|
+
$percentage,
|
|
152
|
+
'$percentage',
|
|
153
|
+
'number'
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Все параметры прошли валидацию - выполняем смешивание цветов.
|
|
159
|
+
@else {
|
|
160
|
+
|
|
161
|
+
// Формула смешивания: создаем промежуточный цвет между
|
|
162
|
+
// $color-from и $color-to с указанным процентным соотношением.
|
|
163
|
+
//
|
|
164
|
+
// Используем встроенную функцию color.mix():
|
|
165
|
+
// Параметры:
|
|
166
|
+
// - $color-to: первый цвет для смешивания
|
|
167
|
+
// - $color-from: второй цвет для смешивания
|
|
168
|
+
// - $percentage * 1%: процентное соотношение
|
|
169
|
+
// (сколько процентов $color-from в смеси)
|
|
170
|
+
//
|
|
171
|
+
// Математика смешивания:
|
|
172
|
+
// - При $percentage = 0% → 100% $color-to, 0% $color-from
|
|
173
|
+
// - При $percentage = 50% → 50% $color-to, 50% $color-from
|
|
174
|
+
// - При $percentage = 100% → 0% $color-to, 100% $color-from
|
|
175
|
+
//
|
|
176
|
+
// Ключевая особенность: функция является оберткой над
|
|
177
|
+
// color.mix() с добавлением валидации параметров и
|
|
178
|
+
// преобразованием процентов в правильный формат.
|
|
179
|
+
@return color.mix($color-to, $color-from, $percentage * 1%);
|
|
180
|
+
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
}
|