توجيهات التحكم: @if و @else if و @else
المنطق الشرطي في SASS
توفر SASS توجيهات تحكم قوية تسمح لك بكتابة منطق شرطي في أوراق الأنماط الخاصة بك. توجيهات @if و @else if و @else تمكنك من إنشاء CSS بشكل مشروط بناءً على قيم المتغيرات، أو إجراء حسابات مختلفة، أو إنشاء أنظمة أنماط تكيفية. هذا يجعل أوراق الأنماط الخاصة بك أكثر ديناميكية وذكاءً.
صيغة @if
يقيّم توجيه @if شرطاً ويتضمن كتلة من الأنماط فقط إذا كان الشرط صحيحاً. الصيغة بسيطة ومشابهة لعبارات الشرط في لغات البرمجة الأخرى.
مثال أساسي على @if
$theme: dark;
.header {
@if $theme == dark {
background-color: #333;
color: #fff;
}
}
// CSS المجمع:
// .header {
// background-color: #333;
// color: #fff;
// }
// إذا كان $theme هو 'light'، لن يتم إنشاء أنماط لـ .header
// استخدام @if في قيم الخصائص
$enable-shadows: true;
.card {
padding: 20px;
border-radius: 8px;
@if $enable-shadows {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
}
// مع تمكين الظلال:
// .card {
// padding: 20px;
// border-radius: 8px;
// box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
// }
@else if و @else
يمكنك توسيع عبارات @if بـ @else if لاختبار شروط متعددة، و @else لتوفير احتياطي عندما لا تُستوفى أي شروط.
سلسلة شرطية كاملة
$size: medium;
.button {
@if $size == small {
padding: 8px 16px;
font-size: 14px;
} @else if $size == medium {
padding: 12px 24px;
font-size: 16px;
} @else if $size == large {
padding: 16px 32px;
font-size: 18px;
} @else {
// احتياطي افتراضي
padding: 10px 20px;
font-size: 15px;
}
}
// CSS المجمع (مع $size: medium):
// .button {
// padding: 12px 24px;
// font-size: 16px;
// }
// شروط متعددة مع خصائص مختلفة
$layout: grid;
$columns: 3;
.container {
display: flex;
@if $layout == grid {
display: grid;
@if $columns == 2 {
grid-template-columns: repeat(2, 1fr);
} @else if $columns == 3 {
grid-template-columns: repeat(3, 1fr);
} @else if $columns == 4 {
grid-template-columns: repeat(4, 1fr);
} @else {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
} @else if $layout == flex {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
}
// CSS المجمع:
// .container {
// display: flex;
// display: grid;
// grid-template-columns: repeat(3, 1fr);
// }
الصحة والزيف في SASS
فهم ما تعتبره SASS "صحيحاً" و "زائفاً" أمر حاسم لكتابة منطق شرطي صحيح. في SASS، يُعتبر قيمتان فقط زائفتين: false و null. كل شيء آخر، بما في ذلك السلاسل النصية الفارغة والصفر والقوائم الفارغة، يُعتبر صحيحاً.
القيم الصحيحة والزائفة
// قيم زائفة
$value1: false;
$value2: null;
// قيم صحيحة (كل شيء آخر!)
$value3: true;
$value4: 0; // صحيح بشكل مفاجئ!
$value5: ""; // أيضاً صحيح!
$value6: (); // القائمة الفارغة صحيحة!
$value7: #000; // أي لون صحيح
// أمثلة
.test-1 {
@if $value1 {
color: red; // غير مضمنة (false)
}
}
.test-2 {
@if $value2 {
color: blue; // غير مضمنة (null)
}
}
.test-3 {
@if $value4 {
color: green; // مضمنة! (0 صحيح)
}
}
// CSS المجمع:
// .test-3 {
// color: green;
// }
// التحقق من null مقابل false
$border-width: null;
.element {
@if $border-width {
border: $border-width solid #ccc;
} @else {
border: none;
}
}
// النتيجة: border: none;
// كن حذراً مع الصفر!
$margin: 0;
.container {
@if $margin {
margin: $margin; // هذا سيتم تضمينه!
}
}
// النتيجة: margin: 0;
@if $value != 0 بدلاً من @if $value.
عوامل المقارنة
تدعم SASS جميع عوامل المقارنة القياسية لبناء شروط معقدة.
جميع عوامل المقارنة
// == (يساوي)
$color: blue;
.equal-test {
@if $color == blue {
background: $color; // مضمنة
}
}
// != (لا يساوي)
$theme: light;
.not-equal-test {
@if $theme != dark {
background: white; // مضمنة
}
}
// < (أقل من)
$width: 500px;
.less-than-test {
@if $width < 600px {
max-width: 100%; // مضمنة
}
}
// > (أكبر من)
$font-size: 18px;
.greater-than-test {
@if $font-size > 16px {
line-height: 1.6; // مضمنة
}
}
// <= (أقل من أو يساوي)
$count: 5;
.less-equal-test {
@if $count <= 5 {
display: grid; // مضمنة
}
}
// >= (أكبر من أو يساوي)
$priority: 10;
.greater-equal-test {
@if $priority >= 10 {
z-index: 1000; // مضمنة
}
}
// مقارنة السلاسل النصية
$alignment: center;
.string-compare {
@if $alignment == center {
text-align: center; // مضمنة
}
}
// مقارنة الألوان
$bg: #fff;
.color-compare {
@if $bg == white {
color: black; // مضمنة (أسماء الألوان تتحلل إلى hex)
}
}
العوامل المنطقية
توفر SASS عوامل منطقية لدمج شروط متعددة: and و or و not.
عامل AND
// and - يجب أن يكون كلا الشرطين صحيحاً
$is-premium: true;
$is-active: true;
.user-badge {
@if $is-premium and $is-active {
background: gold;
color: white;
}
}
// مجمع: background: gold; color: white;
// شروط AND متعددة
$screen-size: 1024px;
$orientation: landscape;
$high-res: true;
.responsive-layout {
@if $screen-size >= 1024px and $orientation == landscape and $high-res {
// يجب أن تكون الشروط الثلاثة صحيحة
background-image: url('hero-large@2x.jpg');
}
}
عامل OR
// or - يجب أن يكون شرط واحد على الأقل صحيحاً
$device: mobile;
.menu {
@if $device == mobile or $device == tablet {
display: none; // مخفية على الجوال أو الجهاز اللوحي
}
}
// تسلسل شروط OR
$role: editor;
.admin-panel {
@if $role == admin or $role == editor or $role == moderator {
display: block;
} @else {
display: none;
}
}
// دمج AND و OR (استخدم الأقواس للوضوح)
$user-level: 5;
$is-verified: true;
$is-subscriber: false;
.premium-content {
@if ($user-level >= 5 and $is-verified) or $is-subscriber {
opacity: 1;
pointer-events: auto;
} @else {
opacity: 0.5;
pointer-events: none;
}
}
عامل NOT
// not - ينفي الشرط
$dark-mode: false;
.content {
@if not $dark-mode {
background: white;
color: black;
}
}
// NOT مع المقارنات
$width: 300px;
.container {
@if not ($width > 500px) {
// مكافئ لـ: @if $width <= 500px
max-width: 100%;
}
}
// NOT مع فحص null
$custom-font: null;
.text {
@if not $custom-font {
font-family: Arial, sans-serif; // استخدم الافتراضي
} @else {
font-family: $custom-font;
}
}
// تعبيرات منطقية معقدة
$has-errors: true;
$is-loading: false;
$is-empty: false;
.form-state {
@if not $has-errors and not $is-loading and not $is-empty {
border-color: green; // حالة نجاح
}
}
@if ($a and $b) or ($c and $d)
استخدام @if في الـ Mixins للمخرجات الشرطية
واحد من أقوى تطبيقات @if هو إنشاء mixins التي تولد CSS مختلفاً بشكل مشروط بناءً على المعاملات.
Mixin استجابي مع الشروط
// mixin نقطة التوقف مع @if
@mixin respond-to($breakpoint) {
@if $breakpoint == phone {
@media (max-width: 599px) {
@content;
}
} @else if $breakpoint == tablet {
@media (min-width: 600px) and (max-width: 1023px) {
@content;
}
} @else if $breakpoint == desktop {
@media (min-width: 1024px) {
@content;
}
} @else if $breakpoint == large-desktop {
@media (min-width: 1440px) {
@content;
}
} @else {
@warn "نقطة التوقف '#{$breakpoint}' غير معروفة.";
}
}
// الاستخدام
.sidebar {
width: 100%;
@include respond-to(tablet) {
width: 300px;
}
@include respond-to(desktop) {
width: 350px;
}
}
// mixin متغير الزر
@mixin button-variant($style: solid, $color: blue) {
@if $style == solid {
background-color: $color;
color: white;
border: 2px solid $color;
&:hover {
background-color: darken($color, 10%);
}
} @else if $style == outline {
background-color: transparent;
color: $color;
border: 2px solid $color;
&:hover {
background-color: $color;
color: white;
}
} @else if $style == ghost {
background-color: transparent;
color: $color;
border: none;
&:hover {
background-color: rgba($color, 0.1);
}
}
}
.btn-primary {
@include button-variant(solid, #007bff);
}
.btn-secondary {
@include button-variant(outline, #6c757d);
}
.btn-link {
@include button-variant(ghost, #007bff);
}
Mixin التباعد مع التحكم في الاتجاه
@mixin spacing($size: md, $type: margin, $direction: all) {
$sizes: (
xs: 4px,
sm: 8px,
md: 16px,
lg: 24px,
xl: 32px
);
$value: map-get($sizes, $size);
@if not $value {
@error "الحجم '#{$size}' غير موجود. استخدم: xs، sm، md، lg، xl";
}
@if $direction == all {
#{$type}: $value;
} @else if $direction == vertical {
#{$type}-top: $value;
#{$type}-bottom: $value;
} @else if $direction == horizontal {
#{$type}-left: $value;
#{$type}-right: $value;
} @else if $direction == top {
#{$type}-top: $value;
} @else if $direction == bottom {
#{$type}-bottom: $value;
} @else if $direction == left {
#{$type}-left: $value;
} @else if $direction == right {
#{$type}-right: $value;
} @else {
@warn "الاتجاه '#{$direction}' غير معروف.";
}
}
// الاستخدام
.card {
@include spacing(md, padding, all);
// النتيجة: padding: 16px;
}
.header {
@include spacing(lg, margin, vertical);
// النتيجة: margin-top: 24px; margin-bottom: 24px;
}
.sidebar {
@include spacing(xl, padding, right);
// النتيجة: padding-right: 32px;
}
استخدام @if في الدوال للقيم المُرجعة الشرطية
الدوال المدمجة مع @if تسمح لك بإرجاع قيم مختلفة بناءً على الشروط، مما ينشئ خدمات مساعدة ذكية.
إرجاع شرطي في الدوال
// تحديد لون النص بناءً على سطوع الخلفية
@function text-color($bg-color, $threshold: 60%) {
@if lightness($bg-color) > $threshold {
@return #000; // نص داكن للخلفيات الفاتحة
} @else {
@return #fff; // نص فاتح للخلفيات الداكنة
}
}
.button-light {
$bg: #f0f0f0;
background-color: $bg;
color: text-color($bg);
// النتيجة: color: #000;
}
.button-dark {
$bg: #2c3e50;
background-color: $bg;
color: text-color($bg);
// النتيجة: color: #fff;
}
// الحصول على قيمة مع احتياطي
@function get-theme-value($key, $fallback: null) {
$theme: (
primary: #007bff,
secondary: #6c757d,
success: #28a745
);
@if map-has-key($theme, $key) {
@return map-get($theme, $key);
} @else if $fallback {
@warn "مفتاح الموضوع '#{$key}' غير موجود. استخدام الاحتياطي.";
@return $fallback;
} @else {
@error "مفتاح الموضوع '#{$key}' غير موجود ولا يوجد احتياطي.";
}
}
.element {
color: get-theme-value(primary);
// النتيجة: color: #007bff;
}
.fallback-element {
color: get-theme-value(unknown, #999);
// تحذير صادر، النتيجة: color: #999;
}
// حساب حجم استجابي
@function responsive-size($min, $max, $viewport-width) {
@if $viewport-width < 768px {
@return $min;
} @else if $viewport-width >= 768px and $viewport-width < 1200px {
// استيفاء خطي بين الحد الأدنى والأقصى
$progress: ($viewport-width - 768px) / (1200px - 768px);
@return $min + ($max - $min) * $progress;
} @else {
@return $max;
}
}
// تحويل الوحدة مع التحقق
@function to-rem($value) {
@if type-of($value) != number {
@error "يجب أن تكون القيمة رقماً. حصلت على: #{type-of($value)}";
}
@if unitless($value) {
@warn "القيمة ليس لها وحدة. افتراض بكسلات.";
$value: $value * 1px;
}
@if unit($value) == "rem" {
@return $value;
} @else if unit($value) == "px" {
@return ($value / 16px) * 1rem;
} @else {
@error "لا يمكن تحويل #{unit($value)} إلى rem.";
}
}
أمثلة من العالم الواقعي
نظام تبديل الموضوع
// تكوين الموضوع
$current-theme: dark;
$themes: (
light: (
bg-primary: #ffffff,
bg-secondary: #f8f9fa,
text-primary: #212529,
text-secondary: #6c757d,
border-color: #dee2e6
),
dark: (
bg-primary: #212529,
bg-secondary: #343a40,
text-primary: #f8f9fa,
text-secondary: #adb5bd,
border-color: #495057
)
);
// الحصول على قيمة الموضوع
@function theme($key) {
$theme-map: map-get($themes, $current-theme);
@if not $theme-map {
@error "الموضوع '#{$current-theme}' غير موجود.";
}
@if map-has-key($theme-map, $key) {
@return map-get($theme-map, $key);
} @else {
@error "المفتاح '#{$key}' غير موجود في الموضوع '#{$current-theme}'.";
}
}
// تطبيق الموضوع
body {
background-color: theme(bg-primary);
color: theme(text-primary);
}
.card {
background-color: theme(bg-secondary);
border: 1px solid theme(border-color);
color: theme(text-primary);
}
.muted-text {
color: theme(text-secondary);
}
مساعد استجابي مع كشف نقطة التوقف
// mixin طباعة استجابية
@mixin responsive-font($min-size, $max-size, $min-vw: 320px, $max-vw: 1200px) {
font-size: $min-size;
@if $min-size != $max-size {
@media (min-width: $min-vw) {
font-size: calc(
#{$min-size} + #{strip-unit($max-size - $min-size)} *
((100vw - #{$min-vw}) / #{strip-unit($max-vw - $min-vw)})
);
}
@media (min-width: $max-vw) {
font-size: $max-size;
}
}
}
@function strip-unit($value) {
@return $value / ($value * 0 + 1);
}
// الاستخدام
h1 {
@include responsive-font(24px, 48px);
}
p {
@include responsive-font(14px, 18px);
}
أنماط واعية بالاتجاه (دعم RTL)
// اتجاه اللغة
$direction: ltr; // يمكن أن يكون 'ltr' أو 'rtl'
@mixin margin-start($value) {
@if $direction == rtl {
margin-right: $value;
} @else {
margin-left: $value;
}
}
@mixin margin-end($value) {
@if $direction == rtl {
margin-left: $value;
} @else {
margin-right: $value;
}
}
@mixin padding-start($value) {
@if $direction == rtl {
padding-right: $value;
} @else {
padding-left: $value;
}
}
@mixin padding-end($value) {
@if $direction == rtl {
padding-left: $value;
} @else {
padding-right: $value;
}
}
// الاستخدام
.sidebar {
@include margin-end(20px);
// LTR: margin-right: 20px;
// RTL: margin-left: 20px;
}
.content {
@include padding-start(30px);
// LTR: padding-left: 30px;
// RTL: padding-right: 30px;
}
.icon {
@if $direction == rtl {
transform: scaleX(-1); // قلب الأيقونات في RTL
}
}
تمرين 1: بناء نظام الأزرار
أنشئ نظام أزرار شامل باستخدام شروط @if:
- أنشئ
@mixin button($size, $variant, $state)يقبل ثلاثة معاملات - خيارات الحجم: small و medium و large (حشو وحجم خط مختلف)
- خيارات المتغير: solid و outline و ghost (أنماط خلفية وحدود مختلفة)
- خيارات الحالة: normal و disabled و loading (عتامة ومؤشر مختلف)
- استخدم عبارات @if متداخلة للتعامل مع جميع التركيبات
- أنشئ 6 فئات أزرار مختلفة تجمع بين هذه الخيارات
تمرين 2: دالة التحقق من الموضوع
قم ببناء نظام موضوع مع التحقق:
- أنشئ خريطة $themes مع 3 موضوعات على الأقل (light و dark و high-contrast)
- يجب أن يحتوي كل موضوع على: خلفية ونص وألوان أساسية وثانوية ونجاح وخطأ
- اكتب
@function theme-color($theme-name, $color-key)التي تعيد اللون - استخدم @if للتحقق من وجود كل من الموضوع ومفتاح اللون
- أرجع رسائل @error مناسبة للمدخلات غير الصالحة
- أضف @warn لأسماء الألوان المهملة
- أنشئ CSS للبطاقات والأزرار والتنبيهات باستخدام دالة الموضوع الخاصة بك
تمرين 3: نظام تباعد ذكي
أنشئ نظام تباعد ذكي:
- اكتب دالة
@function smart-space($multiplier, $context) - خيارات السياق: compact و normal و spacious (وحدة أساسية: 4px و 8px و 12px)
- استخدم @if للتحقق مما إذا كان $multiplier سالباً أو صفراً أو موجباً
- قدم @warn للقيم السالبة
- أنشئ
@mixin apply-spacing($type, $direction, $multiplier, $context) - النوع: margin أو padding
- الاتجاه: all و vertical و horizontal و top و right و bottom و left
- أنشئ 10 فئات خدمية باستخدام هذا النظام