灵访谈非常有幸能邀请到 “魔法哥” 做一期专访。我们都知道您是国内知名的 CSS 专家,是什么样的 “CSS 情结” 使得您愿意将 “CSS魔法” 作为自己的别名?
大家好,很荣幸接受图灵的专访。我叫 “CSS魔法”,熟悉我的朋友都叫我 “魔法哥”。
这个问题问得好,瞬间把我的思绪拉回八年之前——那时我刚开始系统地学习前端知识。当时为了找一份前端工作,我把市面上所有的 CSS 书籍全部买来,全部啃光,迅速且系统地掌握了 CSS 的基础知识。
在这一堆书里,有一套上下册教程叫作《Eric Meyer 谈 CSS》(是由图灵引进的哦)。我记得很清楚,书里有这么一段话:“在准备好语义化的结构之后,我们再给它施加一点儿 CSS 魔法……” 我当时感觉这句话正好契合 CSS 带给我的体验!
我很喜欢 CSS 这门技术,它优雅、神奇、充满魔力,短短几行代码就可以让我们的网页脱胎换骨、焕然一新。于是从那时起,我就开始使用 “CSS魔法” 这个网名了,以这个名字注册了微博;后来还创建了 “CSS魔法” 微信公众号,分享自己在前端领域的学习经验;在为图灵翻译《CSS 揭秘》一书时,也很自然地以此为笔名了。
说到 Eric Meyer,他还是《CSS 权威指南》的作者,也是我的偶像。从偶像那里得来一个名字,很荣幸;而且这其中也有图灵的功劳,也是缘份。
请简单介绍一下您在百姓网的工作内容吧!
我目前在百姓网担任手机站的前端架构师。比较尴尬的是,“前端架构师” 这个头衔经常遭遇质疑:“前端居然也需要架构?” 所以我也趁这个机会阐述一下,我理解中的前端架构到是什么。
其实不管是前端还是后端,任何一项严肃的、长期的、大规模的工程,都是需要有人来设计架构的。
百姓网的前端架构目标很明确:随着业务规模的扩张和团队的壮大,整个网站系统的复杂度也随之迅速上升;如何化繁为简、帮助业务工程师高效高质完成开发任务,这正是前端架构师的职责和挑战所在。
因此,简单概括一下,我在百姓网所做前端架构工作包括:
除此以外,长年重构代码也都是份内事,偶尔还需要投身业务开发。毕竟架构层作为业务层的坚实后盾,松懈不得啊!
您觉得哪些 CSS 知识是必须掌握的?
对一个专业的 CSS 开发者来说,首先,CSS 2 的核心知识必须完全掌握。以《CSS 权威指南》(第三版)为例,除了 “声音样式” 之外,这本书的所有内容都是应该透彻理解的。即使记不住某些冷僻属性的名称与行为,也需要知道在哪里可以快速查阅。
接下来,关于 CSS 3,很多同学都问过我这样一个问题:“魔法哥,现在浏览器都支持 CSS 3 了,我跳过 CSS 2 直接学 CSS 3 可以吗?”
在回答这个问题之前,我们需要先搞清楚 “CSS 3” 到底是什么。读过《CSS 揭秘》这本书的同学应该都很清楚了,“CSS 3” 是一个俗称,并不是 W3C 的官方术语。基本上它表示 CSS 2 之后更新或新增的 CSS 规范模块的合称。
实际上,CSS 3 相对于 CSS 2 并不是类似软件版本更替那样的升级。CSS 2 的全称是 “CSS Level 2”,后续的 CSS 规范并不是完全以替代品的形态出现的,某些 Level 3 的 CSS 规范模块(或新增的规范模块)往往是基于 CSS 2 来扩展的。
因此,对于 CSS 学习者来说,如果买了一本只讲 CSS 3 新增内容的教程或参考书,那还需要搭配 CSS 2 的书来看。事实上,由于篇幅所限,市面上绝大部分以 “CSS 3” 为卖点的图书确实都不会重复讲解 CSS 2 的内容。看到这里,相信上面的问题在大家心中已经得出答案了吧。
我自己的学习路径是这样的:通过《CSS 权威指南》和《精通 CSS》等 CSS 2 时代的经典教程来打好 CSS 2 的基础(因为 CSS 2 已经完全稳定了);对后续新技术和新规范的了解和掌握,通常求助于 MDN 等在线资源(因为变化相当快)。如果新入门的同学面对庞杂的 CSS 体系感觉无从下手,不妨参考这条路径。
有图灵社区网友提问:您在工作中常用的 CSS 实用技巧有哪些?
首先,我会毫不犹豫地推荐大家使用 CSS 预处理器。由于 CSS 并不是编程语言,并不具备抽象能力,当网站的规模发展到一定程度之后,原生 CSS 很难解决抽象与复用的问题。而预处理器则正好弥补了 CSS 在这方面的不足。
即使你不打算学习预处理器的特有语法,甚至还有些排斥,那也不妨尝试利用它的模块机制来拆分和组织代码。由于预处理器大多兼容 CSS 原生语法,因此你可以保持原来写代码的习惯,仅利用预处理器在模块化方面的功能。
对于多人合作的团队来说,通过模块来拆分代码尤为重要。虽然引入预处理器会要求你在工作流中加入构建环节,但我认为这个成本是完全值得的。
接下来,想跟大家分享的经验就是:做好 CSS 代码的 “分层”。我设计的 CSS 架构通常都会由 “Normalize + Reset → 通用基础样式 → UI 组件 → 页面通用的布局框架 → 单个页面的布局和样式” 这几个层级构成,越往左越靠近架构,越往右越靠近业务。
划好层级并把代码写到正确的层级去,可以带来很多好处:在团队分工上,可以把不同层级的代码交给不同的人来开发和维护,相当于关注点分离;从架构角度来看,也可以实现 “控制复杂度” 这一重要目的。
还有就是善用工具。比如通过 Lint 程序来保障代码规范的执行,通过构建工具来让重复劳动尽可能自动化,通过 Autoprefixer 这样的工具来加工或生成代码,等等。俗话说,磨刀不误砍柴工,多看多听多试,用开放的心态去了解和尝试新工具,往往会有不错的收获。
如果这位网友想问的是 “有哪些实用的 CSS 特性”,那我觉得至少要提一下 Flexbox。它是 CSS 3 引入的更强大、更易用的布局方式,而且我们在移动端已经可以安全地使用 Flexbox 的基础特性了。其它的特性,比如高级选择符、渐变、动画等高级特性,也非常有价值,我在编写 CMUI 这个框架时都有实际应用。
此外,大家可能还想了解在编写 CSS 时需要掌握的原则和思路。这里我会推荐《CSS 揭秘》这本书中的 “CSS 编码技巧” 一节。我一直想写篇文章来讲述自己多年积累的 CSS 经验,但一直苦于找不到合适的切入点,总怕挂一漏万。而当我读到这一节时终于释然——原来已经有人帮我做了这件事情!随后我也将它亲手翻译了出来,也算了却了一桩心事。
前端领域的技术更新非常快,常常是一门技术还没学明白,另一门技术又火了,你是如何取舍的呢?
确实,近些年前端领域的新技术、新工具、以及新的实践方式都层出不穷,稍不留神就会有落伍的感觉。而每个人精力都是有限的,面对这样的局面,难免会有一种疲于奔命的压迫感。
我自己的应对方式是抓住核心,放弃自己很难精通的、一时用不到的、或者对当下想做的事情价值不大的技术方向。比如一路以来,我放弃了富媒体方向的 Flash,放弃了图形与游戏方向的 Canvas 和 WebGL,放弃了单页应用方向的 MV*,放弃了语言方向的 FP,等等。
当然这些 “放弃” 都是战略性的,而不是永久性的。毕竟精力有限,不可能面面俱到。不过,一旦某个方向变成自己必须攻克的战略要地,那我也必然会义无反顾跃入新坑。
除了在技术范畴内作取舍,我还会把一部分精力放在 “人” 身上——就是写代码的这群人。个人英雄的时代一去不复返了,单打独斗能力再强,也难成气候。因此,帮助身边的小伙伴快速成长,打造一支梯队完备、技能互补的前端开发团队,往往更具现实意义。有些时候,这也可以成为一种 “突破瓶颈” 的解决方案——每当团队里的小伙伴攻克了某项新技术时,我都可以宽慰自己:我不会,没关系,有小伙伴可以顶上!
有图灵社区网友提问:CSS 与它的小伙伴儿 JavaScript 的关系是怎样的?有什么共同点和差异?
哇噢,这个问题完全是面试题的既视感啊!好的,我来好好回答一下,重温被面试的感觉。
根据 Web 标准的 “分离” 原则,网页界面由三层构成:结构层、表现层、行为层。这三者在技术上分别由 HTML、CSS、JS 来实现。大家都知道有句话叫 “术业有专攻”,在网页上也是一样,不同的层应该由不同的技术来实现。
在近些年,CSS 的能力得到了不少提升,比如 :hover 伪类的增强以及 :checked、:target 等新伪类的出现,令原本只能由 JS 实现的交互功能也可以用 CSS 来实现了。这意味着,在某些场景下,这两者的功能有重叠的地方。
不过从原理上来说,CSS 只具备修改渲染树的能力,无法修改 DOM 结构(“渲染树” 是指 DOM 树在应用样式之后产生的、用于渲染网页界面的数据模型)。CSS 可以通过 display、visibility、opacity等属性来控制元素的显隐,但无法…………
……
点赞+转发,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓-_-)
关注 {我},享受文章首发体验!
每周重点攻克一个前端技术难点。更多精彩前端内容私信 我 回复“教程”
原文链接:https://github.com/cssmagic/blog/issues/63
者:YGYOO
转发链接:https://juejin.im/post/5b8905456fb9a01a105966b4
常,作为开发人员,我们会编写类似类型的代码,陷入一种虽然舒适但有时感觉很平凡的模式。
然而,JavaScript 的世界是广阔的,充满了高级功能,当发现和使用这些功能时,可以将我们的开发工作变得更加令人兴奋和充实。
在本指南中,我们将揭晓 25 个高级 JavaScript 功能,这些功能不仅能揭示这些隐藏的瑰宝,还能将您对 JavaScript 的掌握提升到前所未有的水平。
让我们一起踏上这段发现之旅,将 JavaScript 的高级功能集成到我们的编码库中,以创建更高效、更优雅、更强大的应用程序。是时候为我们的开发任务注入新的乐趣和创造力了。
JavaScript 允许标记循环和块语句,从而可以使用 和 进行精确break控制continue。
outerLoop: for (let i = 0; i < 5; i++) {
innerLoop: for (let j = 0; j < 5; j++) {
if (i === 2 && j === 2) break outerLoop;
console.log(`i=${i}, j=${j}`);
}
}
逗号运算符允许按序列计算多个表达式,并返回最后一个表达式的结果。
let a = (1, 2, 3); // a = 3
除了创建字符串之外,标记模板还可用于 DSL(域特定语言)、清理用户输入或本地化。
function htmlEscape(strings, ...values) {
// Example implementation
}
尽管不推荐,但 JavaScript 允许在块内声明函数,这可能会导致非严格模式下的不同行为。
if (true) {
function test() { return "Yes"; }
} else {
function test() { return "No"; }
}
test(); // Behavior varies depending on the environment
该void运算符计算任何表达式,然后返回 undefined,这对于 JavaScript 的超链接很有用。
void (0); // returns undefined
位运算符(例如|and &)可以更快地执行某些数学运算,但会牺牲可读性。
let floor = 5.95 | 0; // Fast way to do Math.floor(5.95)
该with语句扩展了块的作用域链,允许您编写更短的代码。但是,出于可读性和性能方面的考虑,不建议这样做。
with(document.getElementById("myDiv").style) {
background = "black";
color = "white";
}
与 Christian Heilmann 一起提高您的 JavaScript 技能 - 从今天开始编写更干净、更快、更好的代码!
JavaScript 尝试修复缺失的分号,但依赖它可能会导致意外结果。
let x = 1
let y = 2
[x, y] = [y, x] // Without proper semicolons, this could fail
检查对象是否具有属性,而无需直接访问其值。
"toString" in {}; // true
instanceof检查原型链,同时typeof返回一个字符串,指示未计算的操作数的类型。
function Person() {}
let person = new Person();
console.log(person instanceof Person); // true
console.log(typeof person); // "object"
ES6允许函数具有块作用域,类似于let和const。
{
function test() {
return "block scoped";
}
}
console.log(typeof test); // "function" in non-strict mode, "undefined" in strict mode
使用该debugger语句暂停执行并打开调试器。
function problematicFunction() {
debugger; // Execution pauses here if the developer tools are open
}
eval将字符串作为 JavaScript 代码执行,但会带来重大的安全性和性能影响。
eval("let a = 1; console.log(a);"); // 1
利用 InMotion Hosting 的一系列计划(从共享服务器到 VPS 以及专用服务器)为您的项目找到合适的托管解决方案。
虽然__proto__广泛支持设置对象的原型,但它是非标准的。使用Object.getPrototypeOf()andObject.setPrototypeOf()代替。
let obj = {};
obj.__proto__ = Array.prototype; // Not recommended
document.write()直接写入 HTML 文档,但使用它可能会产生负面影响,特别是对于同步加载外部脚本。
document.write("<h1>Hello World!</h1>");
JavaScript 允许链式赋值,它可以在一个语句中将单个值分配给多个变量。
let a, b, c;
a = b = c = 5; // Sets all three variables to the value of 5
该in运算符检查对象中是否存在属性,而无需访问属性值。
const car = {
make: 'Toyota',
model: 'Corolla'
};
console.log('make' in car); // true
为对象分配属性时,如果属性名称与变量名称相同,则可以使用简写。
const name = 'Alice';
const age = 25;
const person = { name, age };
您可以将默认参数值与函数参数中的解构结合起来,以获得更具可读性和更灵活的函数定义。
function createPerson({ name = 'Anonymous', age = 0 } = {}) {
console.log(`Name: ${name}, Age: ${age}`);
}
createPerson({ name: 'Alice' }); // Name: Alice, Age: 0
createPerson(); // Name: Anonymous, Age: 0
使用该方法快速初始化具有特定值的数组fill()。
const initialArray = new Array(5).fill(0); // Creates an array [0, 0, 0, 0, 0]
利用可调节 LED 照明优化您的工作空间,提高工作效率和舒适度,为专注的工作会议创造理想的环境。
使用 方法可以轻松检查数组中是否存在元素includes(),这比使用 更具可读性indexOf()。
const fruits = ['apple', 'banana', 'mango'];
console.log(fruits.includes('banana')); // true
当destructuring一个对象时,您可以使用别名将属性分配给具有不同名称的变量。
const obj = { x: 1, y: 2 };
const { x: newX, y: newY } = obj;
console.log(newX); // 1
??仅在处理null或时用于提供默认值undefined,而不是其他falsy值,例如
const count = 0;
console.log(count ?? 10); // 0, because count is not null or undefined
使用对象字面量中的计算属性名称创建具有动态名称的函数。
const dynamicName = 'func';
const obj = {
[dynamicName]() {
return 'Dynamic Function Name!';
}
};
console.log(obj.func()); // "Dynamic Function Name!"
使用哈希#前缀定义类中的私有字段,该字段无法从类外部访问。
class Counter {
#count = 0;
increment() {
this.#count++;
}
getCount() {
return this.#count;
}
}
当我们结束对 25 个 JavaScript 高级功能的探索时,JavaScript 的库既庞大又强大。
我们深入研究的每个功能都为解决编码挑战开辟了新途径,类似于在我们的工具包中添加创新工具。
这不仅增强了我们创造性、高效地制定解决方案的能力,而且还强调了 JavaScript 的动态多功能性。
这些高级功能凸显了持续学习在 Web 开发领域的关键作用。
接受这些细微差别并将它们集成到我们的日常编码实践中,使我们能够提高我们的技能并为网络技术的发展做出贡献。
请记住,掌握 JavaScript 的道路是一个持续的旅程,每一行代码都提供了发现非凡事物的机会。
让我们不断突破 JavaScript 所能实现的极限,保持好奇心并对未来的无限可能性保持开放态度。
*请认真填写需求信息,我们会在24小时内与您取得联系。