搞响应式布局判断窗口尺寸,还抱着min和max不放?新比较运算符真香啊

3,132字
13–20 分钟
in

CSS媒体查询里头新出的比较运算符(><>=<==)能直接写宽度范围判断,比如(width >= 768px)这种写法,比老掉牙的min-widthmax-width组合起来要简洁一大截。这篇东西盘一盘新老语法的区别,带几个真实案例的完整操作流程,看完直接给项目换上这套新写法。

目录

老语法长啥样

媒体查询这玩意儿就像给浏览器装了个安检门,只有满足特定条件才放行某套样式。以前最常用的条件是“屏幕类型”加上“窗口宽度范围”。比如想在大屏上(宽度至少30em)搞个特殊布局,老写法长这样:

/* 只有屏幕设备且宽度≥30em才生效 */
@media screen and (min-width: 30em) {
  .box {
    background: #f0f0f0;
  }
}

要是想限定一个区间,比如宽度在400px到1000px之间,就得用andmin-widthmax-width串起来:

@media (min-width: 400px) and (max-width: 1000px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

这种写法有个小毛病——一眼看过去不太直观,脑子里得转个弯:“min-width是大于等于,max-width是小于等于”。而且两个条件用and连起来,代码量也蹭蹭涨。要是断点多几个,整个样式表里密密麻麻全是min-max-,看着就头大。

新运算符咋用

Media Queries Level 4规范整了一套新活:直接用数学比较符号来写条件。width >= 600px这种写法,跟平常写代码的判断逻辑一模一样,大脑不用再翻译一遍。下表把新旧对应关系捋清楚了:

老语法新语法
min-width: 320pxwidth >= 320px
max-width: 320pxwidth <= 320px
没法直接写 > 或 <width > 320px
没法直接写 =width = 320px

范围区间写法更是绝了:以前(min-width: 400px) and (max-width: 1000px),现在直接写成(400px <= width <= 1000px)。左边下限右边上限,一目了然,跟数学里的区间表示法一模一样。

实际操作的时候,比如想给平板设备(768px到1024px)单独调样式:

/* 新语法:窗口宽度在768~1024px之间 */
@media (768px <= width <= 1024px) {
  .sidebar {
    display: block;
    width: 30%;
  }
}

需要留意浏览器兼容性这块,Chromium内核从104版开始支持,Firefox是63版,Safari直到16.4版才跟上。如果项目还要照顾老版Safari(比如16.3及更早),就得备一份老语法当降级方案。可以这么搞:

/* 降级方案:老语法兜底 */
@media (min-width: 768px) and (max-width: 1024px) {
  .sidebar { display: block; width: 30%; }
}

/* 新语法:支持的浏览器会覆盖上面的规则 */
@supports (width >= 1px) {
  @media (768px <= width <= 1024px) {
    .sidebar { display: block; width: 30%; }
  }
}

真实案例整活

拿一个常见的响应式页面来实操:顶部导航栏、主标题区、配图区。移动端(宽度<768px)导航菜单默认隐藏;平板端(768px~999px)导航变成横向排列,标题字号加大;桌面端(≥1000px)整个主区域切成12列网格,标题压在图上面,再加个浮动按钮。

第一步:写基础样式(所有尺寸通用)

/* 移动端默认样式 */
header {
  display: flex;
  justify-content: center;
  padding: 1rem;
}
.nav-list {
  display: none;  /* 小屏上隐藏导航菜单 */
}
.title h1 {
  font-size: 2.5rem;
}
.images {
  position: relative;
}
.floating-btn {
  display: none;  /* 按钮默认隐藏 */
}

第二步:平板断点用新语法

/* 窗口宽度在768px到999px之间时 */
@media (768px <= width <= 999px) {
  header {
    justify-content: space-between;
  }
  .nav-list {
    display: flex;
    gap: 2rem;
  }
  .title h1 {
    font-size: 3.75rem;
  }
}

第三步:桌面断点用新语法

/* 窗口宽度≥1000px时 */
@media (width >= 1000px) {
  main {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 1rem;
  }
  .title {
    grid-column: 1 / 7;
    grid-row: 1;
  }
  .title h1 {
    font-size: 5.75rem;
  }
  .images {
    grid-column: 7 / 13;
    grid-row: 1 / 3;
  }
  .floating-btn {
    display: block;
    position: absolute;
    bottom: 2rem;
    right: -1rem;
  }
}

跑一下浏览器,缩放窗口到各个区间,样式切换丝般顺滑。写这段代码的时候有个小细节:区间写法(768px <= width <= 999px)两边都带等号,意思是包含768px和999px这两个临界点。如果希望临界点只归给某一端,可以改用<>,比如(width > 768px) and (width < 1000px)就不包含两端。

边界坑咋填

老语法里有个经典翻车现场——用min-widthmax-width同时匹配同一个宽度值。假设想在窗口≤320px时用A样式,>320px时用B样式,新手容易这么写:

@media (max-width: 320px) { /* A样式 */ }
@media (min-width: 320px) { /* B样式 */ }

这时候窗口宽度刚好等于320px,两个媒体查询同时命中!A和B样式会打架,后声明的会覆盖前一个,但往往不是想要的效果。有人为了避开这问题,把第二个改成min-width: 321px,结果320px到321px之间那一丁点宽度(比如设备像素比导致的实际渲染宽度是320.5px)两边都不匹配,出现一段空白,页面样式突然“闪”一下。

新语法用比较运算符直接解决了这个尴尬:

/* 严格小于等于320px */
@media (width <= 320px) { /* A样式 */ }

/* 严格大于320px,等于的情况不会进来 */
@media (width > 320px) { /* B样式 */ }

width > 320px只匹配大于320px的情况,320px本身只触发第一个查询,边界干干净净。同理,如果想在某个宽度搞一套独占样式,比如窗口正好等于768px时显示特殊提示框:

@media (width = 768px) {
  .tip {
    display: block;
    content: "窗口宽度正好是768px";
  }
}

实际操作中遇到一个真实案例:有个电商网站的商品卡片在991px和992px之间来回横跳,因为用了max-width: 991pxmin-width: 992px,中间1px的缝隙导致卡片布局闪烁。换成(width <= 991px)(width >= 992px)问题依旧——因为991.5px这种半像素仍然漏掉。最后用(width < 992px)(width >= 992px)才彻底搞定,小于992px的统统归第一套,等于或大于992px的归第二套,没有漏网之鱼。这套新语法就像给媒体查询装上了精确制导,指哪打哪。