搞网页开发这摊子事,最怕的就是吭哧吭哧写完代码,一上线发现浏览器压根不买账。最近圈子里头又冒出一堆新东西,像什么跨页面视频状态保持、媒体查询命名、CSS布局的门道,听着都挺唬人。但别慌,今儿咱就撸起袖子,把这些个技术点掰开揉碎了,用最实在的操练流程给大伙儿盘一盘,保证看完就能上手试试。
一、视频状态跨页保存,这操作有点骚
你有没有碰见过这种糟心情况:在一个页面看视频看到一半,点个链接跳转到其他页面,再退回来,好家伙,视频直接从头开始了,之前看到哪全忘光光。这体验简直拉胯到不行。其实这里头藏着个挺硬核的玩法,就是用上那个叫视图过渡的CSS技术,再配合JavaScript的偷梁换柱,能把视频状态牢牢记住。
存状态
先得把视频当前播放时间、是否在播放这些关键信息给抓下来。这一步要在页面即将跳转的瞬间动手,也就是监听那个pageswap事件。这哥们儿就像一个尽职的会计,在页面交接班的时候,把所有账目(视频状态)都一笔笔记下来。把这些信息捣鼓成一个JSON格式的字符串,然后塞进sessionStorage这个临时仓库里。这仓库跟标签页是同生共死的,只要不关标签页,数据就丢不了。
// 在页面跳转前,把视频状态存进sessionStorage
window.addEventListener('pageswap', (event) => {
// 找到那个视频元素,假设它的id是myVideo
const video = document.querySelector('#myVideo');
if (video) {
const videoState = {
currentTime: video.currentTime,
isPlaying: !video.paused
};
// 转成字符串存起来,这就好比给视频状态拍了个快照
sessionStorage.setItem('videoState', JSON.stringify(videoState));
}
});干这事儿的时候有个小细节得留心:pageswap事件里头的DOM还是旧页面的,所以获取视频元素完全没问题。但要是视频是通过某些动态加载的框架(比如React、Vue)渲染的,得确保在页面卸载前,视频元素还老老实实待在DOM树里头。
恢复状态
页面跳转完成,新页面闪亮登场的时候,得赶紧把之前存的快照掏出来,给视频状态恢复如初。这时候得靠pagereveal事件来打前站。它在新页面内容还没完全展示出来之前就会触发,是最佳的恢复时机。从sessionStorage里把那个JSON字符串捞出来,解析成对象,然后找到新页面里的视频元素,把播放时间和播放状态给它怼回去。
// 新页面展示前,把状态恢复
window.addEventListener('pagereveal', (event) => {
const savedState = sessionStorage.getItem('videoState');
if (savedState) {
const videoState = JSON.parse(savedState);
const video = document.querySelector('#myVideo');
if (video) {
// 先把时间设置好,就像把书签插回书里
video.currentTime = videoState.currentTime;
// 如果之前是在播放状态,那就自动开播
if (videoState.isPlaying) {
video.play().catch(e => console.log('播放被浏览器拦了', e));
}
// 快照用完了就删掉,省得下次误用
sessionStorage.removeItem('videoState');
}
}
});恢复的时候可能会遇到音频卡顿一下下,毕竟视频播放器得重新加载资源,这属于正常现象。另外,视频元素得确保加载完成,loadedmetadata事件是个不错的搭档,可以等元数据加载完再设置currentTime,会更稳当。play()方法调用可能会被浏览器拦截,所以最好包在try...catch里,或者给用户一个按钮,让用户主动点一下开始播放,这样体验会更丝滑。
二、媒体查询咋取名,层叠大法来帮忙
写响应式页面,媒体查询那一堆代码常常搞得人头大。什么@media (max-width: 768px),到处复制粘贴,改个断点得翻遍整个样式表。有没有啥法子给这些媒体查询起个名字,像变量一样用起来?这就要祭出CSS层叠层这个神器了。
定义命名层
思路其实不复杂,就是把不同用途的媒体查询样式塞到不同的层里,然后用层的名字来“命名”这个查询。比如,可以把所有针对平板的样式都放在一个叫tablet的层里,把所有针对桌面端的样式放在desktop层里。虽然不能直接写@media tablet,但通过层叠层的优先级管理,效果上差不多。
/* 先定义层的顺序,越靠后的层优先级越高 */
@layer base, tablet, desktop;
/* 基础样式放在base层 */
@layer base {
.container {
width: 100%;
padding: 1rem;
}
}
/* 平板样式放在tablet层,并且只在屏幕大于768px时生效 */
@layer tablet {
@media (min-width: 768px) {
.container {
max-width: 720px;
margin: 0 auto;
}
}
}
/* 桌面样式放在desktop层,只在屏幕大于1024px时生效 */
@layer desktop {
@media (min-width: 1024px) {
.container {
max-width: 960px;
padding: 2rem;
}
}
}这么做的好处是,所有的媒体查询逻辑都封装在对应的层里,修改起来特别直观。想要调整平板的断点,只需要去@layer tablet里头改,不会误伤其他样式。层的顺序决定了优先级,desktop层在最后,所以它的样式会覆盖前面层的同名样式,这符合移动优先的设计思路。
三、CSS布局搞不懂,盒子模型得拎清
很多新手朋友写布局,感觉就像在玩俄罗斯方块,这里调调那里改改,莫名其妙就乱了。其实根本原因是对CSS的布局原理一知半解。搞懂浏览器怎么摆放元素,这事儿比啥都重要。
先搞清盒子模型
每个元素在页面上都是一个盒子。这盒子有内容区(content)、内边距(padding)、边框(border)和外边距(margin)。默认情况下,给元素加宽高,指的是内容区的宽高,加上padding和border,盒子实际占的空间会比设定的宽高大。这在做精确布局的时候就容易翻车。
<style>
/* 经典盒子模型,宽高只管内容区 */
.box {
width: 200px;
padding: 20px;
border: 1px solid #ccc;
/* 实际占宽 = 200 + 40 + 2 = 242px */
}
/* 换用border-box,宽高就包含padding和border了,舒坦多了 */
.box-alternative {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 1px solid #ccc;
/* 实际占宽 = 200px,padding和border向内缩 */
}
</style>一劳永逸的法子,是在全局把盒子模型改成border-box,这样写宽高的时候心里就有谱了,不会出现“明明设了200px咋给我占了250px”这种灵异事件。大多数现代CSS重置都会做这一步。
布局模式别乱用
搞清楚盒子模型后,就得看怎么把这些盒子排排坐了。这里有几种常见的布局模式:
- 正常流:块级元素(div、p)从上到下堆叠,行内元素(span、a)从左到右排列。这是默认模式,适合文档流内容。
- 浮动:早年用的多,让元素脱离正常流,向左或向右靠。但浮动元素会影响后面的内容,得用清除浮动来擦屁股。
- Flexbox:一维布局神器,适合做导航栏、卡片列表这种要么横向、要么纵向的排列。通过
justify-content和align-items可以轻松搞定对齐问题,不用再算margin。 - Grid:二维布局大佬,能同时控制行和列。做复杂页面整体框架时,Grid简直就是亲爹。能轻易实现像杂志那种错落有致的布局。
下面用Flexbox做一个常见的三明治布局:顶部导航、中间内容、底部页脚。
<style>
body {
margin: 0;
display: flex;
flex-direction: column;
min-height: 100vh; /* 让身体至少撑满整个视口高度 */
}
header {
background: #f0f0f0;
padding: 1rem;
}
main {
flex: 1; /* 这个关键,让主要内容区域吃掉所有剩余空间 */
padding: 1rem;
}
footer {
background: #333;
color: #fff;
padding: 1rem;
}
</style>
<body>
<header>这是脑袋</header>
<main>这是身子,永远会把脚丫子挤到底部</main>
<footer>这是脚丫子</footer>
</body>这里flex: 1是精髓,它告诉浏览器,在垂直方向上,main元素要占满除了header和footer之外的所有剩余空间。这样不管内容多还是少,页脚都会老老实实待在底部,比用绝对定位去戳屁股优雅多了。
