效果演示
Desktop端
iPad/Mobile端
Flex布局
Flexbox 布局总结
1. Flex 容器属性:
display
:定义为 flex 容器。flex-direction
:主轴方向(行或列)。flex-wrap
:控制换行行为。justify-content
:主轴对齐方式(左右或上下)。align-items
:交叉轴对齐方式(纵向对齐)。align-content
:多行对齐方式(仅当有换行时有效)。
2. Flex 项目属性:
order
:改变项目的顺序。flex-grow
:控制项目扩展。flex-shrink
:控制项目收缩。flex-basis
:定义项目的初始尺寸。flex
:flex-grow
、flex-shrink
和flex-basis
的简写。align-self
:单个项目的交叉轴对齐。
Flex 布局属性总结
Flexbox(弹性盒子布局)提供了一套强大的布局工具,既适用于复杂的网页布局,又能处理响应式设计。其主要属性可以分为两类:
- Flex 容器属性(控制容器的布局行为)
- Flex 项目属性(控制容器内子元素的布局行为)
一、Flex 容器属性
-
display
- 定义容器的布局为 flexbox。
display: flex;
或display: inline-flex;
(容器行为类似块级或行内元素)
.container {display: flex; }
-
flex-direction
- 控制主轴(主方向)上项目的排列方向。
row
(默认):水平,从左到右排列。row-reverse
:水平,从右到左排列。column
:垂直,从上到下排列。column-reverse
:垂直,从下到上排列。
.container {flex-direction: row; }
-
flex-wrap
- 控制项目是否换行。
nowrap
(默认):不换行,所有项目都在一行内。wrap
:换行,项目会换行并在多行中排列。wrap-reverse
:换行,但换行方向与wrap
相反。
.container {flex-wrap: wrap; }
-
justify-content
- 在主轴方向上对齐项目,控制项目之间的间隔。
flex-start
(默认):项目靠容器的起始端对齐。flex-end
:项目靠容器的末尾对齐。center
:项目在主轴上居中对齐。space-between
:项目间的间隔相等,第一个项目靠近容器起始端,最后一个项目靠近容器末尾端。space-around
:项目之间的间隔相等,容器两侧的空白间隔也相等。space-evenly
:所有项目之间的间隔相等,包括容器两侧的空白。
.container {justify-content: center; }
-
align-items
- 在交叉轴(垂直于主轴)上对齐项目。
flex-start
:项目靠交叉轴起始端对齐。flex-end
:项目靠交叉轴末尾端对齐。center
:项目在交叉轴上居中对齐。baseline
:项目按文本基线对齐。stretch
(默认):项目拉伸以填充容器。
.container {align-items: center; }
-
align-content
- 控制多行(有换行时)在交叉轴上的对齐方式。
flex-start
:行靠交叉轴的起始位置对齐。flex-end
:行靠交叉轴的末尾位置对齐。center
:行在交叉轴上居中对齐。space-between
:行间隔相等,第一个和最后一个行与容器边缘对齐。space-around
:行间隔相等,行与容器之间也有间隔。stretch
(默认):行拉伸以填充容器。
.container {align-content: space-between; }
二、Flex 项目属性
-
order
- 控制项目的排列顺序,数字越小,排列越靠前,默认为
0
。
.item {order: 1; }
- 控制项目的排列顺序,数字越小,排列越靠前,默认为
-
flex-grow
- 定义项目如何在主轴方向上扩展,以填充容器中剩余的空间。默认为
0
,表示不扩展。 - 如果所有项目的
flex-grow
值相同,空间会均等分配。
.item {flex-grow: 1; }
- 定义项目如何在主轴方向上扩展,以填充容器中剩余的空间。默认为
-
flex-shrink
- 定义项目如何在容器空间不足时缩小。默认为
1
,表示项目会缩小。 - 如果设置为
0
,则项目不会缩小。
.item {flex-shrink: 0; }
- 定义项目如何在容器空间不足时缩小。默认为
-
flex-basis
- 定义项目在分配剩余空间之前的初始大小。默认值为
auto
,即根据项目的内容或宽度来决定。 - 可以设置为具体的像素值、百分比等。
.item {flex-basis: 200px; }
- 定义项目在分配剩余空间之前的初始大小。默认值为
-
flex
flex
是flex-grow
、flex-shrink
和flex-basis
的简写。- 常见的值:
flex: 1
等价于flex-grow: 1; flex-shrink: 1; flex-basis: 0%
,让项目在可用空间中均等分配。- 5:3:2分->flex值分别设为5、3、2
flex: auto
等价于flex-grow: 1; flex-shrink: 1; flex-basis: auto
。flex: none
等价于flex-grow: 0; flex-shrink: 0; flex-basis: auto
,不允许扩展或收缩,保持初始大小。
.item {flex: 1; }
-
align-self
- 控制单个项目在交叉轴上的对齐方式,覆盖
align-items
设置。 - 可选值:
auto
、flex-start
、flex-end
、center
、baseline
、stretch
。
.item {align-self: center; }
- 控制单个项目在交叉轴上的对齐方式,覆盖
Flexbox 为响应式设计提供了非常强大的支持,尤其在复杂布局或动态调整时,能够通过这些属性轻松控制元素的排列、对齐和间距。
媒体查询
媒体查询详解
媒体查询(Media Queries)是 CSS3 提供的一种功能,用于根据设备的特性(如屏幕大小、分辨率、方向等)应用不同的样式,从而实现响应式设计。
媒体查询主要用于适配不同的设备,如桌面、平板、手机等。
1. 基本语法
媒体查询的基本语法如下:
@media media-type and (media-feature: value) {/* CSS规则 */
}
media-type
:媒体类型,例如screen
、print
。media-feature
:媒体特性,例如屏幕宽度、分辨率。value
:具体值,用于定义某个媒体特性的范围或条件。
2. 媒体类型
媒体查询支持以下媒体类型:
媒体类型 | 描述 |
---|---|
all | 默认值,适用于所有设备。 |
screen | 针对屏幕设备,例如电脑、平板、手机等。 |
print | 针对打印设备。 |
speech | 针对屏幕阅读器等语音设备。 |
示例:
@media screen {body {background-color: lightblue;}
}
3. 常用媒体特性
媒体特性用于检测设备的具体属性,以下是常用媒体特性及其说明:
特性 | 描述 |
---|---|
width | 视口(viewport)的宽度。 |
height | 视口的高度。 |
min-width | 视口的最小宽度。 |
max-width | 视口的最大宽度。 |
min-height | 视口的最小高度。 |
max-height | 视口的最大高度。 |
aspect-ratio | 视口的宽高比,例如 16/9 。 |
orientation | 设备方向:portrait (竖屏)或 landscape (横屏)。 |
resolution | 屏幕分辨率,例如 300dpi 或 2dppx 。 |
prefers-color-scheme | 用户的首选颜色模式:light 或 dark 。 |
4. 媒体查询的逻辑运算符
媒体查询支持以下逻辑运算符,允许结合多个条件:
4.1 and
- 用于同时满足多个条件。
@media screen and (min-width: 768px) and (orientation: landscape) {body {background-color: lightgreen;}
}
4.2 not
- 用于排除某些条件。
@media not screen and (max-width: 768px) {body {background-color: pink;}
}
4.3 ,
(逗号,等价于“or”)
- 用于满足任一条件即可生效。
@media (max-width: 768px), (orientation: landscape) {body {font-size: 14px;}
}
5. 媒体查询的使用方式
5.1 在 CSS 文件中
直接在 CSS 文件中使用 @media
:
@media (max-width: 768px) {body {background-color: lightyellow;}
}
5.2 在 <style>
标签中
在 HTML 文件的 <style>
标签中使用:
<style>@media (max-width: 768px) {body {background-color: lightyellow;}}
</style>
5.3 在 HTML 的 <link>
标签中
通过 media
属性为外部 CSS 文件指定条件:
<link rel="stylesheet" href="style.css" media="screen and (max-width: 768px)">
6. 响应式设计中的常用断点
响应式设计中,为不同设备设置“断点”是常见做法。以下是常见设备的屏幕宽度断点:
设备类型 | 常用断点范围 |
---|---|
超小屏幕(手机) | max-width: 576px |
小屏幕(平板) | min-width: 577px 和 max-width: 768px |
中等屏幕(桌面) | min-width: 769px 和 max-width: 992px |
大屏幕(大桌面) | min-width: 993px 和 max-width: 1200px |
超大屏幕 | min-width: 1201px |
示例:
/* 手机样式 */
@media (max-width: 576px) {body {font-size: 14px;}
}/* 平板样式 */
@media (min-width: 577px) and (max-width: 768px) {body {font-size: 16px;}
}/* 桌面样式 */
@media (min-width: 769px) {body {font-size: 18px;}
}
7. 媒体查询的最佳实践
-
优先考虑移动优先设计(Mobile First)
- 先为小屏幕(如手机)编写样式,再为更大的屏幕覆盖样式。
- 使用
min-width
编写媒体查询:
body {font-size: 14px; /* 默认样式 */ }@media (min-width: 768px) {body {font-size: 16px; /* 平板样式 */} }@media (min-width: 992px) {body {font-size: 18px; /* 桌面样式 */} }
-
保持断点清晰
- 确保不同断点之间没有冲突,避免重复规则。
-
避免过多的媒体查询
- 尽量保持规则简单,并利用
flexbox
、grid
等现代布局方法减少依赖媒体查询的需求。
- 尽量保持规则简单,并利用
-
测试多设备
- 使用浏览器的开发者工具测试不同的屏幕尺寸和方向,确保样式正常工作。
8. 示例:完整的响应式布局
/* 默认样式(移动优先) */
body {font-size: 14px;background-color: lightblue;
}/* 平板设备 */
@media (min-width: 768px) {body {font-size: 16px;background-color: lightgreen;}
}/* 桌面设备 */
@media (min-width: 992px) {body {font-size: 18px;background-color: lightcoral;}
}
9. 新特性:容器查询(Container Queries)
容器查询是媒体查询的补充(CSS Container Queries),它允许根据容器的大小而不是视口大小来应用样式。虽然媒体查询以设备为基础,但容器查询更关注组件的自适应。
目前,容器查询还在发展中,部分现代浏览器已经支持。
实现
Pinia全局状态管理
管理当前设备类型(deviceType)、导航条是否需折叠(isCollapse)
Pinia
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useDeviceStore=defineStore('device',{state:()=>({deviceType:"desktop" as deviceType, //初始默认值isCollapse:false,// deviceType:DeviceTypeEnum.Desktop,}),actions:{toggleDevice(type:deviceType){this.deviceType=type;},toggleCollapse(flag: boolean){this.isCollapse=flag;}}
})
监测设备变化
监测视口变化,改变全局状态(deviceType、isCollapse)
Vue2中借助mixin
import store from '@/store'const { body } = document
const WIDTH = 992 // refer to Bootstrap's responsive designexport default {watch: {$route(route) {if (this.device === 'mobile' && this.sidebar.opened) {store.dispatch('app/closeSideBar', { withoutAnimation: false })}}},beforeMount() {window.addEventListener('resize', this.$_resizeHandler)},beforeDestroy() {window.removeEventListener('resize', this.$_resizeHandler)},mounted() {const isMobile = this.$_isMobile()if (isMobile) {store.dispatch('app/toggleDevice', 'mobile')store.dispatch('app/closeSideBar', { withoutAnimation: true })}},methods: {// use $_ for mixins properties// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential$_isMobile() {const rect = body.getBoundingClientRect()return rect.width - 1 < WIDTH},$_resizeHandler() {if (!document.hidden) {const isMobile = this.$_isMobile()store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')if (isMobile) {store.dispatch('app/closeSideBar', { withoutAnimation: true })}}}}
}
mixins: [ResizeMixin],
Vue3中借助组合式API
import { onMounted, onBeforeUnmount, watch } from 'vue';
import { useDeviceStore } from '@/stores/layout'; // 引入 Pinia storeconst WIDTH = 768;
// 参考 Bootstrap 的响应式设计
//常见断点:576mobile\768iPad\992MidDesktop\1200LargeDeasktop\export function useDevice() {const deviceStore = useDeviceStore(); // 使用 Pinia storeconst body = document.body;// 判断当前屏幕是否为移动端const isMobile = () => {const rect = body.getBoundingClientRect();return rect.width - 1 < WIDTH;};// 响应式处理函数const resizeHandler = () => {if (!document.hidden) {const isMobileDevice = isMobile();deviceStore.toggleDevice(isMobileDevice ? 'mobile' : 'desktop');}};// 在组件挂载时进行初始化onMounted(() => {if (isMobile()) {deviceStore.toggleDevice('mobile');deviceStore.toggleCollapse(true);}window.addEventListener('resize', resizeHandler); // 监听窗口大小变化});// 在组件销毁时移除事件监听onBeforeUnmount(() => {window.removeEventListener('resize', resizeHandler);});// 监听设备类型变化,移动设备时关闭侧边栏watch(() => deviceStore.deviceType, (newDevice) => {if (newDevice === 'mobile' && !deviceStore.isCollapse) {deviceStore.toggleCollapse(true);}else {deviceStore.toggleCollapse(false);}});return {isMobile, // 返回判断当前是否为移动设备的方法};
}
<script setup lang="ts">
import {useDevice} from '@/layout/mixin/ResizeHandler'
useDevice();
</script>
媒体查询
不同设备下布局样式调整,调整导航条布局
设备为中小设备时,导航条就折叠且放在最右侧
<div id="app"><!-- 顶部导航栏 --><el-header class="header"><div class="logo">LOGO</div><div class="nav"><Nav></Nav></div><div class="info"><el-row :gutter="20"><el-col :span="8"><theme></theme></el-col><el-col :span="8"><el-icon :size="40"><Git></Git></el-icon></el-col><el-col :span="8"><Translation></Translation></el-col></el-row></div></el-header><!-- 内容区域 --><el-main class="main"><div class="content"><!-- 动态显示内容 --><RouterView></RouterView></div></el-main></div>
///* 响应式布局 */
@media (min-width: 769px) {.logo {font-size: 24px;font-weight: bold;flex:5;}.nav{background-color: transparent;border-bottom: none;flex: 3.5;}.info{flex:1.5;margin-left: 20px;//background-color: white;}
}
@media (max-width: 768px) {.logo {font-size: 24px;font-weight: bold;flex:5;order:0//排序顺序,order属性}.nav{background-color: transparent;border-bottom: none;flex:1;//设备为中小设备时,导航条就折叠且放在最右侧!order:2}.info{flex:4;margin-left: 20px;order:1}}
导航条状态绑定
导航条绑定全局状态(isCollapse)
<template><el-menuclass="menu"mode="horizontal":popper-offset="16"style="max-width: 600px":collapse="deviceStore.isCollapse"></el-menu><script setup lang="ts">
import {useDeviceStore} from '@/stores/layout'
import { watch } from 'vue'
//根据当前窗口大小,判断是否折叠导航条
const deviceStore=useDeviceStore();
watch(()=>deviceStore.isCollapse,(newValue)=>{console.log(newValue)
})
</script>