การใช้ตัวแปร Sass กับ CSS3 Media Queries


121

ฉันกำลังพยายามรวมการใช้ตัวแปร Sass กับคำสั่ง @media ดังนี้:

$base_width:1160px;

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

$base_width จากนั้นกำหนดไว้ที่จุดต่างๆในการวัดเปอร์เซ็นต์ตามความกว้างของสไตล์ชีตเพื่อสร้างเค้าโครงของไหล

เมื่อฉันทำสิ่งนี้ดูเหมือนว่าตัวแปรจะได้รับการยอมรับอย่างถูกต้อง แต่เงื่อนไขสำหรับแบบสอบถามสื่อไม่ได้รับ ตัวอย่างเช่นโค้ดด้านบนจะสร้างเค้าโครง 1160px โดยไม่คำนึงถึงความกว้างของหน้าจอ ถ้าฉันพลิกคำสั่ง @media ดังนี้:

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

สร้างเค้าโครง 960px อีกครั้งโดยไม่คำนึงถึงความกว้างของหน้าจอ โปรดทราบว่าหากฉันลบบรรทัดแรก$base_width: 1160px;จะส่งกลับข้อผิดพลาดสำหรับตัวแปรที่ไม่ได้กำหนด มีความคิดอะไรที่ฉันขาดหายไป?


คำตอบ:


97

นี่เป็นไปไม่ได้เลย เนื่องจากทริกเกอร์@media screen and (max-width: 1170px)เกิดขึ้นในฝั่งไคลเอ็นต์

การบรรลุผลลัพธ์ที่คุณคาดหวังจะเป็นไปได้ก็ต่อเมื่อ SASS คว้ากฎและคุณสมบัติทั้งหมดในสไตล์ชีตที่มี$base_widthตัวแปรของคุณและคัดลอก / เปลี่ยนแปลงตามนั้น

เนื่องจากมันจะไม่ทำงานโดยอัตโนมัติคุณสามารถทำได้ด้วยมือเช่นนี้:

@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
          ...

นี่ไม่ใช่แบบแห้ง แต่ดีที่สุดที่คุณทำได้

หากการเปลี่ยนแปลงเหมือนกันทุกครั้งคุณสามารถเตรียมมิกซ์อินที่มีค่าที่เปลี่ยนแปลงทั้งหมดได้ดังนั้นคุณไม่จำเป็นต้องทำซ้ำ นอกจากนี้คุณสามารถลองรวมมิกซ์อินเข้ากับการเปลี่ยนแปลงเฉพาะ ชอบ:

@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

และ Mixin จะเป็นแบบนี้

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

6
ยังคงเป็นกรณีที่ SASS ใช้ไม่ได้กับตัวแปร $ ในการสืบค้น @media
HappyTorso

1
@HappyTor ดังนั้นจะเป็นเช่นนั้นเสมอไปจนกว่าจะมีสิ่งเช่นนี้เป็นคอมไพเลอร์ Sass ฝั่งไคลเอ็นต์ (เช่นใน JavaScript) ที่ทำงานบนการปรับขนาดวิวพอร์ต ตัวแปร Sass ถูกคอมไพล์เป็นค่าคงที่ในเวลาสร้าง ไม่มีอยู่ในรันไทม์อีกต่อไป แบบสอบถามสื่อได้รับการประเมินที่รันไทม์เมื่อแอตทริบิวต์สื่อในแบบสอบถามเปลี่ยนไป
ericsoco

26
@ericsoco ฉันไม่เห็นว่าทำไมถึงเป็นเหตุผล SASS สามารถ (?) ได้อย่างง่ายดายเพียงแค่ติดตามการใช้งานทั้งหมดของตัวแปรและแทรกคิวรีสื่อที่ใช้ $foo: 1rem; @media (min-width: 10rem) {$foo: 2rem} .class {font-size: $foo} .class2 {padding: $foo}จะส่งผลให้.class {font-size: 1rem} .class2 {padding: 1rem} @media (min-width: 10rem) (.class {font-size: 2rem} .class2 {padding: 2rem}}
powerbuoy

1
ใช่ sass เป็นตัวประมวลผลก่อนไม่มีเหตุผลสำหรับ "สิ่งนี้เป็นไปไม่ได้" ... สามารถทำได้ แต่ไม่ได้ใช้งาน
Ini

54

คล้ายกับคำตอบของ Philipp Zedler คุณสามารถทำได้ด้วย mixin ที่ช่วยให้คุณมีทุกอย่างในไฟล์เดียวหากคุณต้องการ

    @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
ไม่ช้าก็เร็วคุณจะพบปัญหานี้ tho: sitepoint.com/cross-media-query-extend-sass
InsOp

อันนี้ดีกว่าคำตอบของฉัน!
Philipp Zedler

+1 ชอบโซลูชันนี้ รวมสิ่งนี้เข้ากับแผนที่ ( sass-lang.com/documentation/functions/map ) และคุณมีพลังบางอย่าง - ฉันจะหาวิธีแก้ปัญหาแยกต่างหากที่นี่เพื่ออธิบาย แก้ไข: เสร็จสิ้น stackoverflow.com/a/56894640/385273
Ben

9

แก้ไข:โปรดอย่าใช้วิธีนี้ คำตอบโดย ronen ดีกว่ามาก

ในฐานะที่เป็นโซลูชันแบบแห้งคุณสามารถใช้@importคำสั่งภายในแบบสอบถามสื่อเช่นเช่นนี้

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

คุณกำหนดองค์ประกอบตอบสนองทั้งหมดในไฟล์ที่รวมไว้โดยใช้ตัวแปรที่กำหนดในคิวรีสื่อ ดังนั้นสิ่งที่คุณต้องทำซ้ำคือคำสั่งนำเข้า


9

สิ่งนี้ไม่สามารถทำได้กับ SASS แต่เป็นไปได้ด้วยตัวแปร CSS (หรือคุณสมบัติที่กำหนดเองของ CSS ) ข้อเสียเปรียบเพียงประการเดียวคือการรองรับเบราว์เซอร์ แต่จริงๆแล้วมีปลั๊กอิน PostCSS - postcss-css-parametersซึ่ง "แบน" การใช้ตัวแปร CSS (ซึ่งให้การสนับสนุนเบราว์เซอร์รุ่นเก่าด้วย)

ตัวอย่างต่อไปนี้ใช้งานได้ดีกับ SASS (และด้วยตัวแปร postcss-css คุณจะได้รับการสนับสนุนสำหรับเบราว์เซอร์รุ่นเก่าด้วย)

$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);
}

ซึ่งจะส่งผลให้ CSS ต่อไปนี้ แบบสอบถามสื่อซ้ำ ๆ จะเพิ่มขนาดไฟล์ แต่ฉันพบว่าการเพิ่มขึ้นมักจะเล็กน้อยเมื่อใช้เว็บเซิร์ฟเวอร์gzip(ซึ่งโดยปกติจะทำโดยอัตโนมัติ)

.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

ด้วยคำตอบที่ยอดเยี่ยมของ @ ronen และแผนที่มีพลังที่แท้จริง:

    @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
        ));
    }

ตอนนี้เป็นไปได้ที่จะมีการค้นหาสื่อที่แห้งมากขึ้นซึ่งกำหนดเป้าหมาย.myDivด้วยค่าต่างๆมากมาย


เอกสารแผนที่: https://sass-lang.com/documentation/functions/map

ตัวอย่างการใช้แผนที่: https://www.sitepoint.com/using-sass-maps/


ฉันใช้เวลาสักครู่เพื่อดูมัน แต่นี่เป็นเทคนิคเดียวกับคำตอบของ @ ronen เพียงแค่ใช้อินพุตแผนที่เพื่อรองรับตัวแปรหลายตัวพร้อมกัน ฉันไม่ได้ลดมูลค่าด้วยวิธีใด ๆ แต่มันก็ยากที่จะเข้าใจจนกว่าฉันจะเชื่อมต่อนั้น
John Neuhaus

5

ผมมีปัญหาเหมือนกัน.

$menu-widthตัวแปรควรจะ 240px บนมือถือของมุมมอง@media only screen and (max-width : 768px)และ 340px บนเดสก์ท็มุมมอง

ดังนั้นฉันจึงสร้างตัวแปรสองตัว:

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

และนี่คือวิธีที่ฉันใช้:

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

1

คำแนะนำสองข้อ

1 เขียนคำสั่ง CSS "เริ่มต้น" ของคุณสำหรับหน้าจอขนาดเล็กและใช้เฉพาะการสืบค้นสื่อสำหรับหน้าจอขนาดใหญ่ โดยปกติไม่จำเป็นต้องมีการmax-widthสืบค้นสื่อ

ตัวอย่าง (สมมติว่าองค์ประกอบมีคลาส "container")

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

.container {
  width: 960px;

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

2ใช้ตัวแปร CSS เพื่อแก้ปัญหาที่เกิดขึ้นถ้าคุณสามารถ

@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);
}

บันทึก:

เนื่องจากหน้าต่างจะมีความกว้าง 1160px เมื่อหน้าต่างมีความกว้าง 1170px จึงควรใช้ความกว้าง 100% และความกว้างสูงสุด 1160px ดีกว่าและองค์ประกอบหลักอาจมีช่องว่างในแนวนอน 5px ตราบใดที่ คุณสมบัติ box-sizing ถูกตั้งค่าเป็น border-box มีหลายวิธีในการแก้ปัญหา .container { margin: auto }หากผู้ปกครองไม่ได้เป็นเฟล็กซ์หรือตารางภาชนะที่คุณอาจใช้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.