SCSS — это «CSS с суперсилами»: переменные до того, как они появились в CSS, вложение, миксины, циклы, функции. SCSS компилируется в обычный CSS. Несмотря на то, что CSS custom properties закрыли некоторые задачи, SCSS остаётся стандартом в крупных проектах.
// SCSS переменные — компайл-таймные, не runtime
$color-primary: #7b2ff7;
$color-text: #1a202c;
$font-size-base: 16px;
$spacing-unit: 8px;
// Использование
.button {
background: $color-primary;
font-size: $font-size-base;
padding: $spacing-unit * 2 $spacing-unit * 3; // 16px 24px
}CSS custom properties: изменяются в runtime. SCSS-переменные: подставляются при компиляции. Часто используют оба.
.card {
padding: 16px;
border-radius: 8px;
// Дочерние элементы
&__title { // & = .card → .card__title
font-size: 20px;
font-weight: 700;
}
&__body {
color: #666;
}
// Псевдоклассы и псевдоэлементы
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
}
&::before {
content: '';
display: block;
}
// Медиа-запросы внутри компонента
@media (max-width: 768px) {
padding: 12px;
}
}// Определение
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin button-variant($bg, $color: white) {
background: $bg;
color: $color;
border: none;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
&:hover {
background: darken($bg, 10%);
}
}
// Использование
.hero {
@include flex-center;
min-height: 100vh;
}
.button--primary {
@include button-variant(#7b2ff7);
}
.button--danger {
@include button-variant(#ef4444, white);
}%button-base {
display: inline-flex;
align-items: center;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
}
.button {
@extend %button-base;
background: #7b2ff7;
color: white;
}
.button--outline {
@extend %button-base;
background: transparent;
border: 2px solid #7b2ff7;
color: #7b2ff7;
}%placeholder — не попадает в CSS сам по себе, только через @extend.
// _variables.scss
$color-primary: #7b2ff7;
// _mixins.scss
@use 'variables' as vars;
@mixin button {
background: vars.$color-primary;
}
// main.scss
@use 'variables' as v;
@use 'mixins' as m;
.button {
background: v.$color-primary;
@include m.button;
}// @each — перебор значений
$colors: ('primary': #7b2ff7, 'danger': #ef4444, 'success': #10b981);
@each $name, $color in $colors {
.button--#{$name} {
background: $color;
color: white;
}
}
// @for — числовые циклы
@for $i from 1 through 12 {
.col-#{$i} {
width: percentage($i / 12);
}
}
// Генерирует: .col-1 { width: 8.333% } ... .col-12 { width: 100% }@function rem($px, $base: 16) {
@return #{$px / $base}rem;
}
@function spacing($multiplier) {
@return $multiplier * 8px;
}
.container {
padding: rem(24); // 1.5rem
margin-bottom: spacing(3); // 24px
}Симуляция SCSS-компилятора: подстановка переменных и выравнивание вложенности
// Мини SCSS → CSS компилятор
function compileSimpleSCSS(scss) {
const variables = {}
const output = []
// Шаг 1: Собираем переменные ($name: value;)
const varRegex = /\$([\w-]+):\s*([^;]+);/g
let match
while ((match = varRegex.exec(scss)) !== null) {
variables[match[1]] = match[2].trim()
}
// Шаг 2: Подставляем переменные
let processed = scss.replace(/\$([\w-]+)/g, (_, name) => {
return variables[name] || `\$${name}`
})
// Шаг 3: Убираем строки с объявлением переменных
processed = processed.replace(/\$[\w-]+:\s*[^;]+;\n?/g, '')
// Шаг 4: Раскрываем однуровневое вложение
function flattenNesting(css) {
const result = []
const lines = css.split('\n')
let parentSelector = ''
let inNested = false
let depth = 0
let nestedLines = []
for (const rawLine of lines) {
const line = rawLine.trim()
if (!line) continue
depth += (line.match(/\{/g) || []).length
depth -= (line.match(/\}/g) || []).length
if (depth === 0 && line.endsWith('{')) {
parentSelector = line.slice(0, -1).trim()
result.push(`${parentSelector} {`)
inNested = false
} else if (line.startsWith('&')) {
// Псевдоэлемент или класс через &
inNested = true
const childSel = line.replace('&', parentSelector).replace(' {', '')
result.push(` /* nested → ${childSel} */`)
} else if (depth >= 0 && line === '}') {
result.push('}')
} else if (depth > 0) {
result.push(` ${line}`)
} else {
result.push(line)
}
}
return result.join('\n')
}
const flattened = flattenNesting(processed)
console.log('=== Переменные ===')
console.log(variables)
console.log('\n=== Скомпилированный CSS ===')
console.log(flattened)
return flattened
}
const scss = `
\$color-primary: #7b2ff7;
\$spacing: 16px;
\$border-radius: 8px;
.card {
padding: \$spacing;
border-radius: \$border-radius;
background: white;
}
.button {
background: \$color-primary;
padding: 8px \$spacing;
border-radius: \$border-radius;
}
`
compileSimpleSCSS(scss)SCSS — это «CSS с суперсилами»: переменные до того, как они появились в CSS, вложение, миксины, циклы, функции. SCSS компилируется в обычный CSS. Несмотря на то, что CSS custom properties закрыли некоторые задачи, SCSS остаётся стандартом в крупных проектах.
// SCSS переменные — компайл-таймные, не runtime
$color-primary: #7b2ff7;
$color-text: #1a202c;
$font-size-base: 16px;
$spacing-unit: 8px;
// Использование
.button {
background: $color-primary;
font-size: $font-size-base;
padding: $spacing-unit * 2 $spacing-unit * 3; // 16px 24px
}CSS custom properties: изменяются в runtime. SCSS-переменные: подставляются при компиляции. Часто используют оба.
.card {
padding: 16px;
border-radius: 8px;
// Дочерние элементы
&__title { // & = .card → .card__title
font-size: 20px;
font-weight: 700;
}
&__body {
color: #666;
}
// Псевдоклассы и псевдоэлементы
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
}
&::before {
content: '';
display: block;
}
// Медиа-запросы внутри компонента
@media (max-width: 768px) {
padding: 12px;
}
}// Определение
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin button-variant($bg, $color: white) {
background: $bg;
color: $color;
border: none;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
&:hover {
background: darken($bg, 10%);
}
}
// Использование
.hero {
@include flex-center;
min-height: 100vh;
}
.button--primary {
@include button-variant(#7b2ff7);
}
.button--danger {
@include button-variant(#ef4444, white);
}%button-base {
display: inline-flex;
align-items: center;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
}
.button {
@extend %button-base;
background: #7b2ff7;
color: white;
}
.button--outline {
@extend %button-base;
background: transparent;
border: 2px solid #7b2ff7;
color: #7b2ff7;
}%placeholder — не попадает в CSS сам по себе, только через @extend.
// _variables.scss
$color-primary: #7b2ff7;
// _mixins.scss
@use 'variables' as vars;
@mixin button {
background: vars.$color-primary;
}
// main.scss
@use 'variables' as v;
@use 'mixins' as m;
.button {
background: v.$color-primary;
@include m.button;
}// @each — перебор значений
$colors: ('primary': #7b2ff7, 'danger': #ef4444, 'success': #10b981);
@each $name, $color in $colors {
.button--#{$name} {
background: $color;
color: white;
}
}
// @for — числовые циклы
@for $i from 1 through 12 {
.col-#{$i} {
width: percentage($i / 12);
}
}
// Генерирует: .col-1 { width: 8.333% } ... .col-12 { width: 100% }@function rem($px, $base: 16) {
@return #{$px / $base}rem;
}
@function spacing($multiplier) {
@return $multiplier * 8px;
}
.container {
padding: rem(24); // 1.5rem
margin-bottom: spacing(3); // 24px
}Симуляция SCSS-компилятора: подстановка переменных и выравнивание вложенности
// Мини SCSS → CSS компилятор
function compileSimpleSCSS(scss) {
const variables = {}
const output = []
// Шаг 1: Собираем переменные ($name: value;)
const varRegex = /\$([\w-]+):\s*([^;]+);/g
let match
while ((match = varRegex.exec(scss)) !== null) {
variables[match[1]] = match[2].trim()
}
// Шаг 2: Подставляем переменные
let processed = scss.replace(/\$([\w-]+)/g, (_, name) => {
return variables[name] || `\$${name}`
})
// Шаг 3: Убираем строки с объявлением переменных
processed = processed.replace(/\$[\w-]+:\s*[^;]+;\n?/g, '')
// Шаг 4: Раскрываем однуровневое вложение
function flattenNesting(css) {
const result = []
const lines = css.split('\n')
let parentSelector = ''
let inNested = false
let depth = 0
let nestedLines = []
for (const rawLine of lines) {
const line = rawLine.trim()
if (!line) continue
depth += (line.match(/\{/g) || []).length
depth -= (line.match(/\}/g) || []).length
if (depth === 0 && line.endsWith('{')) {
parentSelector = line.slice(0, -1).trim()
result.push(`${parentSelector} {`)
inNested = false
} else if (line.startsWith('&')) {
// Псевдоэлемент или класс через &
inNested = true
const childSel = line.replace('&', parentSelector).replace(' {', '')
result.push(` /* nested → ${childSel} */`)
} else if (depth >= 0 && line === '}') {
result.push('}')
} else if (depth > 0) {
result.push(` ${line}`)
} else {
result.push(line)
}
}
return result.join('\n')
}
const flattened = flattenNesting(processed)
console.log('=== Переменные ===')
console.log(variables)
console.log('\n=== Скомпилированный CSS ===')
console.log(flattened)
return flattened
}
const scss = `
\$color-primary: #7b2ff7;
\$spacing: 16px;
\$border-radius: 8px;
.card {
padding: \$spacing;
border-radius: \$border-radius;
background: white;
}
.button {
background: \$color-primary;
padding: 8px \$spacing;
border-radius: \$border-radius;
}
`
compileSimpleSCSS(scss)Напиши CSS, который имитирует то, что сгенерировал бы SCSS-компилятор. Представь, что у тебя есть SCSS с переменными `$primary`, `$spacing`, `$radius` и вложенными правилами. Напиши итоговый CSS вручную: карточку со стилями, псевдоклассом `:hover` и адаптивным поведением на узких экранах.
SCSS `$primary: #7b2ff7` компилируется в подстановку значения везде. `$spacing: 16px`, `$spacing / 2` = `8px`. `&:hover` → `.card:hover`. `&__title` → `.card__title`. `@media` раскрывается как обычный медиа-запрос.