Sử dụng biến Sass với truy vấn phương tiện CSS3


120

Tôi đang cố gắng kết hợp việc sử dụng biến Sass với các truy vấn @media như sau:

$base_width:1160px;

@media screen and (max-width: 1170px) {$base_width: 960px;}
@media screen and (min-width: 1171px) {$base_width: 1160px;}

$base_width sau đó được xác định tại các điểm khác nhau trong các phép đo dựa trên phần trăm chiều rộng của biểu định kiểu để tạo ra bố cục linh hoạt.

Khi tôi làm điều này, biến dường như được nhận dạng đúng nhưng các điều kiện cho truy vấn phương tiện thì không. Ví dụ: đoạn mã trên tạo ra bố cục 1160px bất kể chiều rộng màn hình. Nếu tôi lật ngược các câu lệnh @media như vậy:

@media screen and (min-width: 1171px) {$base_width: 1160px;}
@media screen and (max-width: 1170px) {$base_width: 960px;}

Nó tạo ra bố cục 960px, một lần nữa bất kể chiều rộng màn hình. Cũng lưu ý rằng nếu tôi xóa dòng đầu tiên, $base_width: 1160px;nó sẽ trả về lỗi cho một biến không xác định. Bất kỳ ý tưởng những gì tôi đang thiếu?


Câu trả lời:


96

Điều này chỉ đơn giản là không thể. Vì trình kích hoạt @media screen and (max-width: 1170px)xảy ra ở phía máy khách.

Bạn chỉ có thể đạt được kết quả mong đợi nếu SASS nắm được tất cả các quy tắc và thuộc tính trong biểu định kiểu có chứa $base_widthbiến của bạn và sao chép / thay đổi chúng cho phù hợp.

Vì nó sẽ không hoạt động tự động nên bạn có thể làm điều đó bằng tay như sau:

@media screen and (max-width: 1170px)
      $base_width: 960px // you need to indent it to (re)set it just within this media-query
      // now you copy all the css rules/properties that contain or are relative to $base_width e.g.
      #wrapper
          width: $base_width
          ...

@media screen and (min-width: 1171px)
    $base_width: 1160px
      #wrapper
          width: $base_width
          ...

Đây không hẳn là KHÔ mà là điều tốt nhất bạn có thể làm.

Nếu các lần thay đổi đều giống nhau, bạn cũng có thể chuẩn bị một mixin chứa tất cả các giá trị thay đổi, vì vậy bạn không cần phải lặp lại nó. Ngoài ra, bạn có thể thử kết hợp mixin với những thay đổi cụ thể. Giống:

@media screen and (min-width: 1171px)
    +base_width_changes(1160px)
    #width-1171-specific-element // additional specific changes, that aren't in the mixin
        display: block

Và Mixin sẽ trông như thế này

=base_width_changes($base_width)
    #wrapper
        width: $base_width

6
Có phải vẫn còn trường hợp SASS không hoạt động với các biến $ bên trong các truy vấn @media không?
HappyTorso

1
@HappyTors Vì vậy, nó sẽ luôn như vậy, cho đến khi có một thứ như trình biên dịch Sass phía máy khách (ví dụ: trong JavaScript) chạy trên chế độ thay đổi kích thước khung nhìn. Các biến Sass được biên dịch thành các giá trị tĩnh tại thời điểm xây dựng; chúng không còn tồn tại trong thời gian chạy. Truy vấn phương tiện được đánh giá trong thời gian chạy, khi các thuộc tính phương tiện trong truy vấn thay đổi.
ericsoco

26
@ericsoco Tôi không hiểu tại sao đó là lý do. SASS có thể dễ dàng (?) Chỉ cần theo dõi tất cả các cách sử dụng của biến và chèn các truy vấn phương tiện vào nơi chúng được sử dụng; $foo: 1rem; @media (min-width: 10rem) {$foo: 2rem} .class {font-size: $foo} .class2 {padding: $foo}sẽ dẫn đến.class {font-size: 1rem} .class2 {padding: 1rem} @media (min-width: 10rem) (.class {font-size: 2rem} .class2 {padding: 2rem}}
powerbuoy 12/09/2016

1
yep sass là một bộ tiền xử lý, không có lý do gì cho "Điều này chỉ đơn giản là không thể" ... Nó có thể làm được, chỉ là nó không được thực hiện.
Ini

54

Tương tự như câu trả lời của Philipp Zedler, bạn có thể làm điều đó với mixin. Điều đó cho phép bạn có mọi thứ trong một tệp duy nhất nếu bạn muốn.

    @mixin styling($base-width) {
        // your SCSS here, e.g.
        #Contents {
            width: $base-width;
        }
    }

    @media screen and (max-width: 1170px) {
        @include styling($base-width: 960px);
    }
    @media screen and (min-width: 1171px) {
        @include styling($base-width: 1160px);
    }

1
sớm hay muộn bạn sẽ gặp phải vấn đề này, tho: sitepoint.com/cross-media-query-extend-sass
InsOp

Cái này tốt hơn câu trả lời của tôi!
Philipp Zedler

+1 thích giải pháp này. Kết hợp điều này với bản đồ ( sass-lang.com/documentation/functions/map ) và bạn đã có một số sức mạnh - Tôi sẽ tạo một giải pháp riêng ở đây để giải thích. Chỉnh sửa: xong. stackoverflow.com/a/56894640/385273
Ben

9

Chỉnh sửa: Vui lòng không sử dụng giải pháp này. Câu trả lời của ronen là tốt hơn nhiều.

Là một giải pháp KHÔ, bạn có thể sử dụng @importcâu lệnh bên trong một truy vấn phương tiện, ví dụ như thế này.

@media screen and (max-width: 1170px) {
    $base_width: 960px;
    @import "responsive_elements";
}
@media screen and (min-width: 1171px) {
    $base_width: 1160px;
    @import "responsive_elements";
}

Bạn xác định tất cả các phần tử đáp ứng trong tệp được bao gồm bằng cách sử dụng các biến được xác định trong truy vấn phương tiện. Vì vậy, tất cả những gì bạn cần lặp lại là câu lệnh nhập.


9

Điều này là không thể với SASS, nhưng có thể với các biến CSS (hoặc thuộc tính tùy chỉnh CSS ). Hạn chế duy nhất là hỗ trợ trình duyệt - nhưng thực sự có một plugin PostCSS - postcss-css-variable - "làm giảm" việc sử dụng các biến CSS (cung cấp cho bạn hỗ trợ cho các trình duyệt cũ hơn).

Ví dụ sau hoạt động hiệu quả với SASS (và với các biến postcss-css, bạn cũng nhận được hỗ trợ cho các trình duyệt cũ hơn).

$mq-laptop: 1440px;
$mq-desktop: 1680px;

:root {
    --font-size-regular: 14px;
    --gutter: 1rem;
}

// The fact that we have to use a `max-width` media query here, so as to not
// overlap with the next media query, is a quirk of postcss-css-variables
@media (min-width: $mq-laptop) and (max-width: $mq-desktop - 1px) {
    :root {
        --font-size-regular: 16px;
        --gutter: 1.5rem;
    }
}

@media (min-width: $mq-desktop) {
    :root {
        --font-size-regular: 18px;
        --gutter: 1.75rem;
    }
}

.my-element {
    font-size: var(--font-size-regular);
    padding: 0 calc(var(--gutter) / 2);
}

Điều này sẽ dẫn đến CSS sau. Các truy vấn phương tiện lặp đi lặp lại sẽ làm tăng kích thước tệp, nhưng tôi nhận thấy rằng sự gia tăng này thường không đáng kể khi máy chủ web áp dụng gzip(điều này thường sẽ tự động làm).

.my-element {
  font-size: 14px;
  padding: 0 calc(1rem / 2);
}
@media (min-width: 1680px) {
  .my-element {
  padding: 0 calc(1.75rem / 2);
  }
}
@media (min-width: 1440px) and (max-width: 1679px) {
  .my-element {
  padding: 0 calc(1.5rem / 2);
  }
}
@media (min-width: 1680px) {
  .my-element {
  font-size: 18px;
  }
}
@media (min-width: 1440px) and (max-width: 1679px) {
  .my-element {
  font-size: 16px;
  }
}

8

Với câu trả lời tuyệt vời của @ ronen và bản đồ, có một số sức mạnh thực sự có sẵn:

    @mixin styling($map) {
        .myDiv {
            background: map-get($map, 'foo');
            font-size: map-get($map, 'bar');
        }
    }

    @media (min-height: 500px) {
        @include styling((
            foo: green,
            bar: 50px
        ));
    }

    @media (min-height: 1000px) {
        @include styling((
            foo: red,
            bar: 100px
        ));
    }

Giờ đây, có thể có nhiều truy vấn phương tiện KHÔ hơn nhắm mục tiêu .myDivvới một loạt các giá trị khác nhau.


Tài liệu bản đồ: https://sass-lang.com/documentation/functions/map

Sử dụng bản đồ mẫu: https://www.sitepoint.com/using-sass-maps/


Tôi mất một giây để xem nó, nhưng đây là kỹ thuật tương tự như câu trả lời của @ ronen, chỉ sử dụng đầu vào bản đồ để hỗ trợ nhiều biến cùng một lúc. Tôi không giảm giá trị của nó bằng bất kỳ cách nào, nhưng nó khó hiểu hơn cho đến khi tôi tạo ra mối liên hệ đó
John Neuhaus

5

Tôi đã từng gặp vấn đề tương tự.

Các $menu-widthbiến nên 240px trên điện thoại di động xem @media only screen and (max-width : 768px)và 340px trên máy tính để bàn xem.

Vì vậy, tôi chỉ cần tạo hai biến:

$menu-width: 340px;
$menu-mobile-width: 240px;

Và đây là cách tôi đã sử dụng nó:

.menu {
    width: $menu-width;
    @media only screen and (max-width : 768px) {
      width: $menu-mobile-width;
    }
}

1

Hai khuyến nghị

1 Viết câu lệnh CSS "mặc định" của bạn cho màn hình nhỏ và chỉ sử dụng truy vấn phương tiện cho màn hình lớn hơn. Thường không cần max-widthtruy vấn phương tiện.

Ví dụ (giả sử phần tử có lớp "vùng chứa")

@mixin min-width($width) {
  @media screen and (max-width: $width) {
    @content;
  }
}

.container {
  width: 960px;

  @include min-width(1170px) {
    width: 1160px;
  }
}

2 Sử dụng các biến CSS để giải quyết vấn đề, nếu bạn có thể .

@mixin min-width($width) {
  @media screen and (max-width: $width) {
    @content;
  }
}

:root {
  --container-width: 960px;
  @include min-width(1170px) {
    --container-width: 1160px;
  }
}

.container {
  width: var(--container-width);
}

Ghi chú:

Vì nó sẽ có chiều rộng là 1160px khi cửa sổ có chiều rộng là 1170px, có thể tốt hơn nếu sử dụng chiều rộng là 100% và chiều rộng tối đa là 1160px và phần tử mẹ có thể có đệm ngang là 5px, miễn là thuộc tính box-sizing được đặt thành border-box. Có rất nhiều cách để giải quyết vấn đề. Nếu vùng gốc không phải là vùng chứa linh hoạt hoặc lưới, bạn có thể sử dụng .container { margin: auto }.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.