前端这几年,技术栈迭代快得让人眼花缭乱,从jQuery到Angular、React、Vue,再到大前端、跨端方案满天飞。很多刚入行的朋友经常问我,到底该追哪个框架、学哪个新工具,生怕一步跟不上就落伍了。但我做了这么多年项目,有个感受越来越强烈:绕了一大圈,真正兜底的永远是HTML、CSS、JavaScript这三件套。所谓“原生开发的尽头是html css js”,不是一句口号,而是技术演进回归本质的必然结果。
这篇文章我想结合自己在大前端项目里的实际经验,聊聊为什么框架和工具只是表象,原生三件套才是前端工程师真正的基本盘。我会从技术演进逻辑讲起,再用一个Vue3 + Element Plus自适应大屏项目做实战拆解,最后整理一份高频踩坑排查手册。无论你是刚接触前端的新人,还是写了几年业务代码想往上走的同学,这篇内容应该都能给你一些参考。
1. 大前端这十年,绕来绕去终归三件套
1.1 框架再花哨,浏览器只认三件套
先想一个问题:你用React写的组件、用Vue写的模板、用Sass写的嵌套样式,最终跑到浏览器里,被解析成的是什么?答案就是HTML、CSS、JavaScript。框架做的事情本质上是“帮助我们更高效地生成这三样东西”,而不是替代它们。
很多人一开始学前端就直接上Vue或React,跳过了原生基础,结果一做项目就露馅。比如组件样式冲突不知道怎么排查,动态绑定的class不生效找不到原因,甚至想给页面某个元素加个最简单的点击事件,都要去翻框架文档。这些问题的根子,就是三件套基本功不扎实。
我见过不少“框架熟练工”,简历上写着精通Vue、React,实际连盒模型、事件冒泡、回流重绘都讲不清楚。框架带来的便捷,让他们误以为自己已经会前端了。可一旦项目遇到性能瓶颈、需要做底层优化、或者框架本身出了奇怪的bug,最终还是得回到原生层面去分析问题。
1.2 跨端方案的尽头,还是“翻译”成原生UI和三件套
大前端这几年最火的词,除了框架本身,就是各种跨端方案。从React Native到Flutter,再到各种小程序框架,表面上看是“用一套代码跑多端”,但如果你深入看它们的底层实现,会发现一个共同点:它们要么把JS逻辑映射成原生组件,要么把布局描述翻译成近似的原生界面。而在Web这个场景里,任何方案想跑在浏览器上,最终输出的仍然逃不开HTML、CSS、JS。
换句话说,你选择什么跨端方案,决定的是“开发时用什么语法”,但决定“运行时怎么渲染”的,依然是浏览器原生支持的Web技术。理解了这一点,你再看前端生态的起起落落,就不会焦虑了。今天火的框架,过几年可能就被新方案替代,但HTML、CSS、JS这套底层能力不会变。它是整个前端行业的“通用语言”。
我在团队里带人的时候,判断一个前端工程师的潜力,不看他会多少个框架,而是看他对三件套的理解深度。能把原生基础吃透的人,换框架就像换工具,适应期很短;原生基础薄弱的人,换个框架就从头学一遍,而且永远学不完。
2. 吃透HTML、CSS、JS,才算真的会前端
2.1 HTML:页面骨架,承载的是语义化和结构思维
HTML看起来最简单,很多人觉得不就是一堆标签嘛,写多了就会了。但真正吃透HTML,你至少得理解两件事:语义化和结构设计。
语义化不是说“用header、nav、main、footer这些标签装样子”,而是让你的页面结构在没有CSS的情况下依然可读、可访问、对搜索引擎友好。我参与过一个政务类项目,对无障碍访问要求很高,屏幕阅读器需要准确朗读页面内容。当时有同事用一堆div套div搭出来的页面,重构时改得痛不欲生。后来全部换成语义化标签,结构清晰了,样式和脚本的耦合度也大幅下降。
再比如表单页面的label与input关联、按钮的type属性、图片的alt描述,这些细节在视觉上几乎看不出差别,但对功能的完整性影响巨大。你写出的HTML是“给人看的”还是“给机器看的”,在复杂项目里会明显拉开差距。
结构思维则是另一个容易被忽略的点。一个页面是分成几个大的区块,每个区块内部怎么嵌套,哪些内容应该用列表、哪些应该用表格,这些决策直接影响后续CSS布局和JS交互的复杂度。好的HTML结构,能让CSS和JS写起来非常顺手;糟糕的结构,后面怎么写都别扭。
2.2 CSS:视觉系统的核心,框架样式本质还是CSS
CSS的水比很多人想象的要深。网上有个搜索热词叫“css定义与引用”,看起来是个入门话题,但实际工作中,样式问题才是前端排查耗时最多的地方。
先说说定义与引用的基础问题。CSS有三种引入方式:行内样式、内部样式表、外部样式表。行内样式优先级最高,但复用性最差;内部样式适合单页demo,不利于缓存;外部样式表才是项目工程化之后的主流选择。一个常见的坑是,有些新手为了省事,把样式全写在行内,结果后期要改主题色,满屏找代码,改到怀疑人生。
再往深了说,CSS的核心难点在于层叠、继承、盒模型和布局体系。我特别推荐大家花时间把“层叠上下文”这个概念搞明白。真正常见的样式bug,比如z-index不生效、position定位偏移、transform影响fixed定位,十有八九都和层叠上下文有关。
现在的前端项目,不管用的是Vue还是React,都离不开UI组件库。拿Element Plus来说,你改它的主题色、覆盖它的默认样式,本质是在写CSS,只不过要跟它的类名优先级做斗争。理解CSS优先级算法(!important、内联、ID、类、标签、通配符),你就能摸清为什么有时候你的样式“死活不生效”,也知道该用什么样的选择器策略去精准覆盖。
CSS还有一层价值,就是审美和用户体验的落地。同一个页面,有人做出来像PPT,有人做出来像设计稿,差别就在CSS细节:间距是否统一、圆角和阴影是否克制、过渡动画是否自然、字体字重是否协调。这些能力框架给不了你,只能靠对CSS的持续打磨。像“css字体渐变”“css涟漪光圈扩散”“css动态相册纯代码”,这些小技巧看着不起眼,但在实际项目中就是提升质感的关键点。
2.3 JS:业务逻辑的灵魂,前端研发真正的门槛
如果说HTML和CSS决定了页面“长什么样”,那JavaScript就决定了页面“能做什么”。从交互逻辑到数据请求,从状态管理到性能优化,前端的复杂度主要集中在JS这一层。
以搜索热词“js判断字符串是否包含”为例,看起来一句话就能答完——可以用indexOf,也可以用includes。但在真实业务里,问题往往没有这么简单。你要考虑大小写是否敏感、是否需要忽略首尾空格、是在浏览器环境还是Node环境跑、对低版本浏览器的兼容性要求是什么。类似的还有“js打开url”“js函数”“js promise”,这些都是业务开发中的高频能力。
我见过很多初级工程师写JS,习惯复制粘贴,出了问题就console.log到处打,找不到根本原因。比如异步问题,因为不懂事件循环和Promise的微任务宏任务机制,导致接口返回数据的顺序总是对不上。比如闭包问题,在循环里绑定事件,结果点击任意按钮拿到的都是最后一个索引。这些例子听起来基础,但在实际代码评审里出现的频率相当高。
JS真正难的地方,不是语法,而是逻辑建模能力。一个商品详情页、一个三级联动选择器、一个复杂的表单校验,业务逻辑怎么抽象、数据怎么流转、边界条件怎么处理,这才是拉开水平的地方。框架能帮你管理DOM和状态,但管理不了你的思路。思路清晰的人,用原生JS也能写出结构优雅的代码;思路混乱的人,用再好的框架也是把业务逻辑堆成一团乱麻。
3. 实战复盘:Vue3 + Element Plus自适应大屏项目怎么落到三件套
3.1 从设计稿到HTML结构:先搭骨架再谈其他
前面的内容偏认知层面,这一节我结合一个真实项目来讲。之前接了一个数据可视化大屏的需求,技术选型是Vue3 + Element Plus + ECharts,这是一个很典型的大前端组合。设计稿宽度是1920px,需要在各种分辨率下自适应展示,这就是搜索热词里大家经常问的“vue3+element plus 前端项目自适应大屏方案”。
很多同学拿到这类需求,第一反应是去搜现成的适配插件。但我的习惯是,先不碰代码,把设计稿在脑子里拆成HTML结构:顶部是标题区,左侧是几个数据卡片,中间是核心图表区域,右侧是排行榜,底部有时钟和滚动公告。这个结构一旦清晰,接下来写template就是按图索骥。
大屏项目的模板层级不宜嵌套过深,一般是“容器页面 → 区域模块 → 内部组件”三层结构。区域模块之间用flex布局平铺,内部组件各自独立。这样做好处很明显:每个区域只对自己负责,后续调整尺寸或替换图表,不会牵一发动全身。如果模板结构本身就乱,后面CSS适配和JS数据流都会跟着乱。
搭结构的时候还要注意一点,就是不要过早引入组件库。先把纯HTML写出来,确认结构的合理性和完整性,再加上样式和交互。组件库是工具,不是骨架。骨架稳定了,组件就是填充材料。
3.2 CSS大屏适配:rem/vw取舍与像素计算逻辑
大屏项目里,样式适配是重头戏。宽度1920的设计稿,要在1366、1440、1600、2560等不同分辨率的屏幕上保持布局不塌、字号协调、图表不挤,需要一套可复用的适配方案。
目前主流做法基本是两条路线:基于rem的缩放方案,和基于vw/vh的等比方案。rem方案的逻辑是,把设计稿宽度等分成若干份,比如按1920除以100,得到1rem等于19.2px。页面根字体的font-size根据当前屏幕宽度动态计算,所有尺寸用rem单位书写,屏幕变化时整体等比缩放。vw方案更直接,直接用视口宽度的百分比,1920设计稿下的1px等于100vw/1920,也就是约0.052vw。
两条路线的取舍,我实践的结论是:纯展示型大屏,vw方案更简洁,因为不需要监听窗口变化、不需要操作根节点的font-size,样式表里按公式换算即可。但如果项目里还有大量表单、列表、弹窗这类对最小可读性有要求的组件,纯等比缩放会把字缩得太小,这时rem方案配合最小字号限制更稳妥。
具体换算方式,拿1920设计稿,除以24得到80,意味着1rem等于80px。写样式的时候,设计稿标注24px的字体,就写0.3rem。这个除数是根据你的设计稿和显示粒度定的,不用照抄别人的配置。只要保证全局统一,就不容易出现样式错乱。
CSS这一层的另一个重点是容器内的文本位置调整。大屏卡片里的标题、数值、单位经常要对齐,我一般用flex的align-items和justify-content配合line-height微调。遇到过不少次,数值和单位基线不齐,用vertical-align又总差几个像素,最后是给具体元素单独设置行高和margin-bottom解决的。这类细节没法靠某个全局方案搞定,只能在组件层级逐个打磨。
3.3 JS逻辑与组件封装:把业务逻辑写清楚
大屏项目的JS部分,一般包括数据获取、组件状态管理、图表option组装、定时刷新逻辑这几块。我用Vue3的组合式API来做,核心是把数据请求和业务处理分离。
比如每个图表组件,只负责接收props、监听数据变化、调用ECharts渲染。数据从哪来、什么时候更新、需要做哪些计算,全部放到页面层的业务逻辑里。这样图表组件可以复用,别的页面要用同一个图,直接传数据就行。
定时刷新是可视化大屏的常见需求。这里有一个很经典的坑:定时器用setInterval,组件销毁时忘记clearInterval,导致页面切走之后接口还在不断请求,控制台报错或者出现内存泄漏。我在项目里用onBeforeUnmount钩子统一清理,并且把定时器的创建和清除逻辑封装成一个可复用的composable,避免在多个组件里重复写还容易出错。
另一个高频需求是三级联动,比如选择省份后加载城市,选择城市后加载区县。用Vue实现时,核心是监听当前级的选择值,触发下一级的数据请求。这个逻辑用原生JS也能写,但Vue的响应式系统让代码更直观:watch到省份变化,重置城市和区县,再请求城市列表。关键在重置逻辑,很多人只写了赋值,忘了清空下一级的历史数据,结果用户切了省份,区县还停留在上一个省份的旧数据上,这种bug很隐蔽,上线了才会被发现。
3.4 盘点框架帮忙做了什么、没帮什么
做完这个项目,正好可以复盘一下Vue3 + Element Plus到底帮了什么忙,又留下了哪些事必须自己搞定。
框架帮我们解决的是:组件化开发的组织方式、响应式数据驱动的视图更新、常见UI组件的成熟封装、脚手架带来的构建流程。这些能力显著提升了开发效率,尤其是Element Plus提供的表格、表单、弹窗、日期选择器等组件,省去了大量重复造轮子的时间。
但框架没帮我们解决的是:项目的HTML结构设计、CSS适配方案、数据流设计、图表交互逻辑、异常场景处理。这些东西都需要你对原生三件套有足够的理解,才能在框架的框架里写出高质量代码。换句话说,框架是顺风船,但航行方向和航线规划还得自己定。
拿Element Plus的自适应来说,它本身提供了栅格系统和响应式断点,能解决一部分布局问题。但大屏场景下,需要的是“等比缩放”而不是“断点重排”,这时候组件库的响应式能力反而不够用,还是要回到CSS层面自己写适配方案。这就是为什么我一直强调,遇到问题先想三件套能不能解决,再想框架能不能帮忙。
4. 为什么说原生开发能力是前端工程师的压舱石
4.1 排查线上问题,最终还是读三件套
前端项目上线后,不可能百分之百没有bug。有的是样式错乱,有的是交互异常,有的是性能卡顿。排查这些问题时,浏览器开发者工具看到的就是HTML结构、CSS样式、JS调用栈。你框架用得再熟,打开DevTools看到的不是Vue组件树,而是渲染之后的DOM节点。
我印象很深的一次排障经历:线上有个页面在低端安卓机上白屏,但本地开发怎么都复现不了。后来一步步排查,发现是某个第三方依赖生成的CSS属性在低版本WebView上不支持,导致整个页面渲染崩溃。这个问题的定位,靠的是对CSS兼容性的了解,而不是对框架的了解。类似的情况还有,某些JS新语法在旧浏览器上直接报错,你看到的是白屏,但根本原因是Babel没有把某个API做polyfill。
建站工具、低代码平台、脚手架,都在不断降低前端开发的门槛。但门槛降低不意味着底层能力不重要,恰恰相反,越是上层工具普及,越需要有人能深入底层解决工具覆盖不到的问题。这些问题的答案,就在HTML、CSS、JS本身。
4.2 性能优化的关键点,都在原生层面
前端性能优化,有一个很经典的误区:一提到优化就想着上CDN、加缓存、开Gzip。这些都是有效手段,但属于工程层面的优化。真正决定页面性能的,往往还是原始代码的质量。
比如首屏加载,如果页面的DOM层级嵌套很深,渲染引擎构建渲染树的时间就会变长。一个具有几十层嵌套的表格,切换列排序时卡顿,优化方式往往是把冗余DOM去掉,而不是给表格组件加什么配置项。再比如动画卡顿,原因通常是触发了大量的回流重绘,解决思路是减少对布局属性的频繁读写、使用transform和opacity替代top和left。这些优化手段,全部围绕HTML结构、CSS渲染机制、JS操作方式展开。
如果你能理解浏览器是如何解析HTML、构建DOM树、应用CSS样式、执行JavaScript的,性能优化就不是靠猜、靠试,而是能一眼看穿瓶颈在哪。这种能力在面试和工作中都是硬通货。
4.3 职业发展的护城河:代码之外的三件套思维
把三件套拓展到思维层面,你会发现它影响的不仅是代码,还有整个职业发展。懂HTML结构的人,设计页面时会考虑模块复用和信息层级;懂CSS的人,能预判视觉方案在不同屏幕上的表现;懂JS的人,能把复杂交互拆解成清晰的状态机。这些思维方式,是在长期和原生技术打交道的过程中练出来的,框架给不了你。
我从团队管理角度观察,能胜任更高级别岗位的工程师,往往不是用了多少新框架、掌握了多少工具链,而是能把业务需求转化为清晰的技术方案。这种转化能力的前提,就是对底层技术有足够的掌控力。HTML、CSS、JS三者,恰好构成了一个完整的“结构-表现-行为”模型,这个模型是分析任何前端问题的通用框架。
所以我的建议是:不要因为框架的火热而轻视原生基础。框架更新速度越来越快,今天的技术热点,过两年可能就成了历史包袱。但三件套的基本原理几乎不变,你投入在这里面的每一分精力,长期来看都是复利。
5. 三件套实战避坑锦囊:高频问题与排查手册
5.1 CSS常见问题:样式不生效、居中失败与优先级混乱
样式问题是前端开发中出现频率最高的,我整理几个高频场景,给大家参考。
样式不生效,第一反应是检查选择器优先级。比如Element Plus组件内部用了两层类名,你可能需要写三个类名才能覆盖默认样式。这时候不要用!important硬顶,正确的做法是查看组件渲染后的DOM结构,找到对应的类名层级,写一个同样优先级或更高优先级的选择器。用!important一时爽,后续要覆盖你的时候就是火葬场。
CSS居中也是一个经典话题。水平居中有text-align、margin: auto、flex + justify-content等方案。垂直居中有line-height等于容器高度、flex + align-items、绝对定位加负margin、transform translate等方案。我的习惯是:单行文本用line-height,块级元素水平居中用margin auto,复杂场景统一用flex。flex是现时代最稳的居中方案,但要注意父容器的宽度和高度是否明确,否则flex也照样不居中。
还有一个高频问题,就是搜索热词里提到的“css 鼠标移入事件”和“css 变形 梯形”。鼠标移入效果用:hover实现,配合transition做过渡动画,要注意的是hover状态下的尺寸变化如果触发了layout,就会出现抖动。变形类需求用transform实现,梯形可以用transform: perspective() + rotateX(),但一定要给父容器设置perspective属性,否则变形效果会和你预期差很远。
5.2 JS常见问题:包含判断、异步时序与事件绑定的坑
JS的坑,很多都是“看似简单,实则暗藏玄机”。比如判断字符串是否包含,indexOf和includes的区别不只是写法不同。includes不能区分字符串与正则,而indexOf会返回位置,所以判断存在性时我习惯用includes,判断位置时用indexOf。如果你要兼容非常老的浏览器,includes要记得打polyfill,否则线上会直接报错。
异步时序问题,我举一个实际例子。页面初始化时,有三个接口需要并发请求,但其中一个接口返回后要立刻渲染图表,另外两个接口返回后要更新表格。如果只用Promise.all,三个接口都返回才能渲染图表,首屏会显得很慢。正确做法是让图表接口独立then,表格接口单独处理,用Promise.all去管理次要数据。
事件绑定方面,最容易被忽略的是事件委托和事件解绑。循环生成的列表项,如果每个都绑一个事件监听,列表多时性能明显下降,还会造成内存占用。正确做法是事件委托,把监听器挂到父级容器上,通过event.target判断点击的是谁。在Vue中,事件绑定由框架管理,但如果你在原生JS里操作DOM,或者使用第三方插件的原生事件,就要特别注意清理。
5.3 常见问题速查表
| 问题现象 | 根本原因 | 快速排查思路 | 我的经验值 |
|---|---|---|---|
| 样式写了没生效 | 选择器优先级不够或被覆盖 | 打开DevTools查看生效的样式规则,比较优先级 | 先看来源和优先级,不要急着加!important |
| 大屏比例不对 | rem/vw换算基准不统一 | 检查根字体动态计算公式和换算系数 | 全项目统一用一个换算函数 |
| 点击事件拿不到正确索引 | 闭包保存了循环变量 | 用let定义循环变量,或使用事件委托绑定data属性 | 事件委托是更彻底的方案 |
| 接口数据返回顺序错乱 | 异步请求没有正确处理竞态 | 使用AbortController取消过期请求,或用最新请求标记校验 | 搜索联想、联动选择尤其要注意竞态 |
| 组件销毁后还在报错 | 定时器或事件监听未清理 | 检查onUnmounted/onBeforeUnmount是否清理了所有副作用 | 写一个统一的清理函数 |
| 样式产生全局污染 | 组件样式未做作用域隔离 | 检查是否使用scoped或CSS Modules | 组件库样式覆盖时要格外小心全局污染 |
| 动画卡顿掉帧 | 触发了大量回流重绘 | 检查动画属性是否为transform/opacity,避免读写布局属性 | 把触发layout的属性与动画属性分离 |
5.4 提升三件套能力的日常训练方法
最后分享几个我平时用来保持原生能力的训练方法。第一个是“每周一个小玩具”,不依赖框架,只用原生HTML/CSS/JS做一个小功能,比如倒计时、轮播图、时钟、拖拽排序。这个习惯能帮你保持对原生API的敏感度。第二个是“读框架编译产物”,用Vue或React写一个小组件,然后去看构建后的源码,你会惊讶地发现框架帮你做了多少事,也会更清楚哪些操作是昂贵的。第三个是“读CSS规范文档”,虽然规范文档枯燥,但很多问题的答案其实都写在里面,比如层叠上下文、包含块、BFC,这些概念一旦吃透,CSS对你来说就是透明的。
我始终认为,学前端不是去背框架API,而是建立一套能解释“页面如何工作”的思维模型。HTML、CSS、JS就是这个模型的三个支柱。大前端概念的流行,让大家把目光都投向了更多复杂的工具和概念,但真正的功夫,还是要回到最基础的地方去练。把三件套学扎实了,你会发现无论是原生开发还是框架开发,事情都变得简单了许多。