整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

2021系列-学好前端?请弄清CSS的这15件事(入

2021系列-学好前端?请弄清CSS的这15件事(入门)

前端开发社区中,被抱怨最多的恐怕就是CSS,因为它真心不容易学。但它功能强大,越深入挖掘CSS的潜能,你就越有机会像魔法师一样释放各种神奇魔力。

无疑,学习CSS相关的基础知识只是一方面,你还需要去学习CSS所具有创造力和可视化事物的能力,这就是本期我们规划了推荐CSS这15个功能的原因。


1 . HTML

跑题了?开篇先说HTML而非CSS?注意!行内人常说,HTML就像 一个人的骨骼与器官,而CSS就是皮肤,有了这两样再去注入灵魂(JS),所以,我想先强调下骨骼和器官的重要性。

如果你先入手了HTML的所有基础知识,自然CSS会变得更加容易。另外,通常我们要完成所需的样式,就需要在方式上有选择性的去构造HTML;诚然,牺牲样式的结构和语义是走不通的,越好的CSS,理论上你的HTML结构也应是越好的,由此一个出色的Web开发人员应该明白如何写好UI,同时不会引入过多不必要的HTML,损害可访问性或者让内容难以管理。


2 . 盒模型

记得之前Flutter有个说法叫“万物皆Widget”,翻译得不错!对于 CSS,

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model

盒子模型几乎是学好CSS的一个"公开的秘密"——margin是你将box分开的距离(边距),

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/margin

border是边框,

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/border

padding是框内内容和边框之间的间隔,这样你的内容可以是其他框或者文本。

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/padding

谈论盒模型经常遗漏的一件事是轮廓(outline),它是位于边框和边距之间的线条,也是可以样式化的。

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/outline

3 . 特异性和级联流程

这个副标题差不多就定义了CSS,CSS又叫级联样式表。

编写CSS时的头号难题是某样式被替换为第三方样式或你自己的样式。虽然现今已经涌现出许多通过隔离样式块来解决类似问题的工具,但是最佳方法是理解和吃透问题本身,包括:浏览器以何种顺序应用样式、如何去覆盖第三方样式、!important标志相关问题等等。

努力遵循CSS流程以及它的工作方式,且你还需要找到一个适合CSS结构,努力坚持使用。


4 . 属性选择器、组合器、伪类以及伪元素

选择器可帮助你定位HTML;组合器可帮助你组合和定位模式;

相关链接:https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators

伪类可帮助你确定状态;

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes

伪元素可帮助你确定或创建HTML的特定部分。

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements

掌握这些对于成为CSS魔法师来说,至关重要。


5 . 变量

变量绝对将CSS带入一个新的高度。虽然CSS具备一些有用的函数,

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions

但离不开变量,因为变量使CSS更加强大......

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties

譬如,变量引入了共享和作用域值的思想。了解如何使用变量的方法能够让你的CSS风格更上一层楼。

我在SCSS上使用变量,但是SCSS是预处理器,意味着一旦CSS到达浏览器,它便不复存在;而使用CSS变量,你可以利用JS对其进行操作,例如在网站上切换暗黑和正常模式。


6 . 显示和定位

CSS'显示和位置‘属性可以帮助我们控制元素在内容流内部和外部的放置方式。任何CSS开发人员都应该掌握这两个属性以及由它们派生出来的一些知识点。在CSS中,定位事物仍然是最大的挑战之一,因此,你必须着重进行学习。


7 . 响应式设计与布局

响应式设计不但能支持网页适配于任何尺寸的屏幕,而且还能调整布局以适应可用空间。

过往,通常我会建议身边的人持续关注CSS媒体查询,

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries

但是,想一想,CSS的发展演进很有些年头了,意味着你如果想要打造响应式的网页,可完全搁置使用媒体查询,改用网格布局(或flexbox)外加CSS clamp函数去控制字体。

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions

响应式与流畅设计完美匹配超越了你对display:flex和网格布局的了解,

相关链接:https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design

没有付出怎有收获?利用响应式设计的前提是,开发者需要了解诸如:设备和视口比例等问题、不同tags在可用空间限制下的表现、HTML的meta tags、既定视口的元素之间的合理距离、不同的设备尺寸等。所有这些都需要不断地去学习和积累经验,大魔法师千万不能小觑他们哟~


8 . 图片和背景

<img />标签和CSS背景两者是并存的,你必须了解何时使用image标签和CSS背景。尤其是CSS背景功能强大,我们甚至可以使用它来创建文本下划线和一些其他出色的背景效果。对我个人来说,它们是CSS中最有趣的部分之一,选入此15件事中,就是提醒你不要忽略它。


9 . 字体

关于字体,开发者往往忽略了一些细节,我感觉它们非常重要——你需要清楚如何为网站优化字体,包括诸如:如何加载它们、有哪些选项、如何控制它们;实际上,很难找到完美的字体,但好的前端必须知道如何就地取材将它们提升到一个新的水平,从细节做起,以帮助到提升页面的整体效果。


10 . 色彩

颜色无处不在。 你可以将其用在边框、背景、轮廓等等。大多数开发者使用纯hex颜色色值或颜色名称,当然也可以通过使用RGBA控制颜色的alpha透明度;基于alpha值,利用HSLA控制hue-rotate、饱和度和亮度,以便进一步提升页面色彩展示效果。

驾驭页面色彩不仅仅是色值的事,CSS currentColor属性也需要纳入管理范畴——

相关链接:https://www.w3schools.com/colors/colors_currentcolor.asp

我们可以在hex颜色值中再添加2个其它值,以控制RGBA颜色的alpha值, 例如:#29910d82是个不透明的绿色,这其中的‘82’控制的是alpha值,类似使用RGBA时的最后一个值。


11. 过渡与动画效果

过渡效果简单说就是一种控制CSS值从状态A变为状态B的方式,

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions

而动画效果是一种使众多的关键帧实现动态画面的方式。

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations

动画一旦使用得当,任何网页都会美不胜收,而动画和过渡效果相结合有利于增强用户体验,从而增强用户与网页之间的互动性。


12. Transform属性

另一种被广泛用来增强网页使用体验的方式就是引入3D效果。

相关链接:https://developer.mozilla.org/en-US/docs/Web/CSS/transform

Transform是那些你日常需要进行动画处理和过渡的内容,自不言说,transform属性与CSS动画+过渡是紧密相关的,这是我推荐它的原因之一;而另一个原因是,近些年,海内外运用Transform属性的网站越来越多,大概率你在未来工作中会用到,值得学习和关注。


13 . 预处理器

CSS的预处理器功能强大,可令我们更得心应手地利用上希望在CSS中注入的东西。它使我们能够桥接上诸如mixins、函数和模块化等概念,此外它还有助于导入和撰写样式。

相关链接:https://sass-lang.com/documentation/syntax

上面给你推荐的是SASS,除了SASS,还有其他预处理器,譬如LESS和Stylus,相对来说,它们仅基于一些语法上的更改,但都殊路同归。

无论你会选择哪种方法,在网页样式例程中引入预处理器都是让你收获颇丰,至少可以帮助你以更少的CSS来创建复杂的样式。


14 . CSS Houdini

CSS Houdini是一个低级的API,通过帮助我们访问到CSS引擎,从而为你提供了一些所需功能去扩展CSS。

相关链接:https://developer.mozilla.org/en-US/docs/Web/Houdini

CSS Houdini不存在等待浏览器的渲染周期的问题,因而解析起来要快得多。再有,它公开了一些被用来对CSS进行模块化的东西,这些称之为worklets,worklets不需要模块化CSS代码的预处理器。 在这样一个简单的API中,应该算是个非常高级的概念了,它让离成为一个魔法师又迈出了一步。


15 . CSS架构

随着你构建的应用体量越来越大,编写CSS时很容易出现冲突,这也是我为什么把CSS架构放到最后单独触及的原因。

在你和你的团队达成意见一致的情况下,采用何种技术方法来帮助你们是当务之急,下面是一些示例:

BEM :是由Yandex团队提出的一种CSS Class 命名方法

相关链接:http://getbem.com/introduction/

OOCSS:面向对象的CSS指南

相关链接:http://oocss.org/

SMACSS :CSS的可扩展模块化体系结构

相关链接:http://smacss.com/

上面这三个都是CSS结构样式指南,你可以按照指南更合理地去构造选择器和样式,甚至还可以根据喜好提出自己的建议。


结论:

晋级CSS是一个连贯性的学习过程,需要大量的实践。如果你无法做到坚持尝试上述这15个方法/概念,同时上手各种项目去进行实践,那么你永远成为不了一位魔法师。

我建议你找些小型CSS项目练练手,我近期也会为你找些github上开源的项目练手,敬请期待。


前在相关的元旦活动中,就已透露后面还有更好的活动及奖励,今天,终于是揭晓了,在元旦过后,拳头及英雄联盟,也是准备迎接新的一年,以及鼓励大家迎接新的一个赛季,即S12。

我想一些召唤师也察觉到,新的一年正式开始,新英雄的预告、新年皮肤、新赛季、新活动等各色内容接踵而至,灰呆都觉得最近新闻太多不知道先写哪个了,咱这就来看看这次的活动。

活动内容

活动时间

任务统计时间为:2022年1月7日0点—2022年2月7日23:59。

奖励领取截止时间:2022年2月13日23:59。

奖励及任务

目标一:进行1场峡谷排位赛

可获得:3胜双倍经验卡×1

?目标二:赢得5场峡谷对局(匹配+排位)

可获得:杰作宝箱+钥匙

?目标三:组队完成1场游戏对局

可获得:随机1个表情

?目标四:组队完成3场游戏对局

可获得:蓝色精萃×500+橙色精萃×500

?目标五:

1.累计12天,当天有完成1场游戏对局

2.累计5天,当天有登录掌上英雄联盟

可获得:随机1个皮肤

?

活动链接:https://lol.qq.com/act/a20220107season/index.html?_code=507041

同样的如果链接挂了的话就去掌盟看看吧~

活动会优先从对应奖池内产出未拥有道具,大家倒是不用担心会抽出重复皮肤,如果是奖池内容已经全收集就会将此皮肤转到其他区的号里,如果真的全收集那也太富了,哈哈哈。

在的app和pc网站做的越来越花哨,但是有时候用户并不喜欢你给他挑选好的主题颜色,这个时候就需要一个换皮肤的功能了。

那么我们怎么在vue中实现这个换皮肤的功能呢?



项目结构

  1. 实现思路
  • 我们用vue一般都是写单页面程序,因此在实际发布的时候只有一个html以及一堆静态文件(js、css、img之类)。而在html中引用了这些js和css。我们要换皮肤的话其实就是动态的去切换css,所以在这里实现换皮肤其实也就是动态的更改html中引用css的路径,使得当用户选择了不同的皮肤,页面引用的css不同从而呈现的样式也不一样。
  1. 优化策略
  • 其实在实际场景中,需要通过切换皮肤来改变css的元素占所有css的比重并不会很多,因此我们需要把需要通过切换改变的css单独提取出来,在动态改变css路径时只需要去改变这个控制皮肤的css就可以了。
  • 把皮肤相关的css压缩。
  1. 实现代码分析
  2. 如下是我们的html代码,注意其中的<link rel="stylesheet" name="theme" href="">,其他的都是正常引用。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
 <title>iView admin</title>
 <meta charset="UTF-8">
 <!-- -->
 <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
 <!-- 引入的css -->
 <link rel="stylesheet" href="/dist/main.css">
 <!-- 注意这是我们换皮肤需要的css -->
 <link rel="stylesheet" name="theme" href="">
 <!-- 图标 -->
 <link rel="icon" href="./td_icon.ico" type="image/x-icon"/>
</head>
<body>
<div id="app"></div>
<!-- 用到的js -->
<script type="text/javascript" src="/dist/vender-base.js"></script>
<script type="text/javascript" src="/dist/vender-exten.js"></script>
<script type="text/javascript" src="/dist/main.js"></script>
</body>
</html>

接下来就是具体实现换皮肤功能了,换皮肤一般都是点击一个按钮弹出一些皮肤的选项,选中选项后皮肤生效。

我们将换皮肤功能抽成一个组件theme-switch。pc端使用iview,手机端使用了vant。一共有3套皮肤用于切换。



目录结构

  • pc端
<template>
 <div style="display:inline-block;padding:0 6px;">
 <Dropdown trigger="click" @on-click="setTheme">
 <a href="javascript:void(0)">
 <Icon :style="{marginTop: '-2px', verticalAlign: 'middle'}" color="#495060" :size="18" type="paintbucket"></Icon>
 <Icon type="arrow-down-b"></Icon>
 </a>
 <DropdownMenu slot="list">
 <DropdownItem v-for="(item, index) in themeList" :key="index" :name="item.name">
 <Row type="flex" justify="center" align="middle">
 <span style="margin-right:10px;"><Icon :size="20" :type="item.name.substr(0, 1) !=='b' ? 'happy-outline' : 'happy'" :color="item.menu"/></span>
 <span><Icon :size="22" type="record" :color="item.element"/></span>
 </Row>
 </DropdownItem>
 </DropdownMenu>
 </Dropdown>
 </div>
</template>
<script>
import Cookies from 'js-cookie';
import config from '../../../../build/config.js';
export default {
 name: 'themeSwitch',
 data () {
 return {
 themeList: [
 {
 name: 'black_b',
 menu: '#495060',
 element: '#2d8cf0'
 },
 {
 name: 'black_g',
 menu: '#495060',
 element: '#00a854'
 },
 {
 name: 'black_y',
 menu: '#495060',
 element: '#e96500'
 }
 ]
 };
 },
 methods: {
 // 点击切换事件
 setTheme (themeFile) {
 let menuTheme=themeFile.substr(0, 1);
 let mainTheme=themeFile.substr(-1, 1);
 if (menuTheme==='b') {
 // 黑色菜单
 this.$store.commit('changeMenuTheme', 'dark');
 menuTheme='dark';
 } else {
 this.$store.commit('changeMenuTheme', 'light');
 menuTheme='light';
 }
 let path='';
 // 取到我们在html上给皮肤的css留的坑并且设置路径
 let themeLink=document.querySelector('link[name="theme"]');
 let userName=Cookies.get('user');
 if (localStorage.theme) {
 let themeList=JSON.parse(localStorage.theme);
 let index=0;
 let hasThisUser=themeList.some((item, i)=> {
 if (item.userName===userName) {
 index=i;
 return true;
 } else {
 return false;
 }
 });
 if (hasThisUser) {
 themeList[index].mainTheme=mainTheme;
 themeList[index].menuTheme=menuTheme;
 } else {
 themeList.push({
 userName: userName,
 mainTheme: mainTheme,
 menuTheme: menuTheme
 });
 }
 localStorage.theme=JSON.stringify(themeList);
 } else {
 localStorage.theme=JSON.stringify([{
 userName: userName,
 mainTheme: mainTheme,
 menuTheme: menuTheme
 }]);
 }
 let stylePath='';
 if (config.env.indexOf('dev') > -1) {
 stylePath='./src/views/main-components/theme-switch/theme/';
 } else {
 stylePath='dist/';
 }
 if (mainTheme !=='b') {
 path=stylePath + mainTheme + '.css';
 } else {
 path='';
 }
 themeLink.setAttribute('href', path);
 }
 },
 created () {
 let path='';
 // 判断运行环境用于切换地址
 if (config.env.indexOf('dev') > -1) {
 path='./src/views/main-components/theme-switch/theme/';
 } else {
 path='dist/';
 }
 let name=Cookies.get('user');
 // 如果用户之前选择过皮肤则直接使用之前选择的,否则使用默认皮肤
 if (localStorage.theme) {
 let hasThisUser=JSON.parse(localStorage.theme).some(item=> {
 if (item.userName===name) {
 this.$store.commit('changeMenuTheme', item.menuTheme);
 this.$store.commit('changeMainTheme', item.mainTheme);
 return true;
 } else {
 return false;
 }
 });
 if (!hasThisUser) {
 this.$store.commit('changeMenuTheme', 'dark');
 this.$store.commit('changeMainTheme', 'b');
 }
 } else {
 this.$store.commit('changeMenuTheme', 'dark');
 this.$store.commit('changeMainTheme', 'b');
 }
 // 根据用户设置主题
 if (this.$store.state.app.themeColor !=='b') {
 let stylesheetPath=path + this.$store.state.app.themeColor + '.css';
 // 取到我们在html上给皮肤的css留的坑并且设置路径
 let themeLink=document.querySelector('link[name="theme"]');
 themeLink.setAttribute('href', stylesheetPath);
 }
 }
};
</script>
  • 手机端
<template>
 <div style="display:inline-block;padding:0 6px;">
 <div @click="showBtn">换皮肤</div>
 <van-actionsheet v-model="show" :actions="themeList" @select="setTheme"/>
 </div>
</template>
<script>
import Cookies from "js-cookie";
import { Actionsheet } from "vant";
// import config from "../../../../build/config.js";
export default {
 name: "themeSwitch",
 components: {
 [Actionsheet.name]: Actionsheet
 },
 data() {
 return {
 show: false,
 themeList: [
 {
 name: "黑色",
 data: "black_b"
 },
 {
 name: "绿色",
 data: "black_g"
 },
 {
 name: "黄色",
 data: "black_y"
 }
 ]
 };
 },
 methods: {
 showBtn() {
 this.show=true;
 },
 setTheme(themeFile) {
 themeFile=themeFile.data;
 let menuTheme=themeFile.substr(0, 1);
 let mainTheme=themeFile.substr(-1, 1);
 if (menuTheme==="b") {
 // 黑色菜单
 this.$store.commit("changeMenuTheme", "dark");
 menuTheme="dark";
 } else {
 this.$store.commit("changeMenuTheme", "light");
 menuTheme="light";
 }
 let path="";
 let themeLink=document.querySelector('link[name="theme"]');
 let userName=Cookies.get("user");
 if (localStorage.theme) {
 let themeList=JSON.parse(localStorage.theme);
 let index=0;
 let hasThisUser=themeList.some((item, i)=> {
 if (item.userName===userName) {
 index=i;
 return true;
 } else {
 return false;
 }
 });
 if (hasThisUser) {
 themeList[index].mainTheme=mainTheme;
 themeList[index].menuTheme=menuTheme;
 } else {
 themeList.push({
 userName: userName,
 mainTheme: mainTheme,
 menuTheme: menuTheme
 });
 }
 localStorage.theme=JSON.stringify(themeList);
 } else {
 localStorage.theme=JSON.stringify([
 {
 userName: userName,
 mainTheme: mainTheme,
 menuTheme: menuTheme
 }
 ]);
 }
 let stylePath='css/';
 // stylePath="./src/view/component/theme-switch/theme/";
 // if (config.env.indexOf('dev') > -1) {
 // stylePath='src/view/component/theme-switch/theme';
 // } else {
 // stylePath='dist/';
 // }
 if (mainTheme !=="b") {
 path=stylePath + mainTheme + ".css";
 } else {
 path="";
 }
 themeLink.setAttribute("href", path);
 this.show=false;
 }
 },
 created() {
 let path="";
 path="css/";
 // if (config.env.indexOf("dev") > -1) {
 // path="src/view/component/theme-switch/theme";
 // } else {
 // path="dist/";
 // }
 let name=Cookies.get("user");
 if (localStorage.theme) {
 let hasThisUser=JSON.parse(localStorage.theme).some(item=> {
 if (item.userName===name) {
 this.$store.commit("changeMenuTheme", item.menuTheme);
 this.$store.commit("changeMainTheme", item.mainTheme);
 return true;
 } else {
 return false;
 }
 });
 if (!hasThisUser) {
 this.$store.commit("changeMenuTheme", "dark");
 this.$store.commit("changeMainTheme", "b");
 }
 } else {
 this.$store.commit("changeMenuTheme", "dark");
 this.$store.commit("changeMainTheme", "b");
 }
 console.log(path);
 // 根据用户设置主题
 if (this.$store.state.app.themeColor !=="b") {
 let stylesheetPath=path + this.$store.state.app.themeColor + ".css";
 let themeLink=document.querySelector('link[name="theme"]');
 themeLink.setAttribute("href", stylesheetPath);
 }
 }
};
</script>

在首页引用该组件,初次渲染时进入该组件的creat方法,如果用户之前选择过皮肤则直接使用之前选择的,否则使用默认皮肤。在store中加入相应方法。

changeMenuTheme (state, theme) {
 state.menuTheme=theme;
},
changeMainTheme (state, mainTheme) {
 state.themeColor=mainTheme;
 }

动态切换最关键的是这两行代码,其他的都是将皮肤状态存起来方便下次使用:

let themeLink=document.querySelector('link[name="theme"]')

themeLink.setAttribute('href', stylesheetPath)

但是这个时候我们皮肤相关的css并没有打到代码中,需要我们额外进行配置。

在webpack的配置文件中找到plugins,加入以下插件:

  • pc端
 new CopyWebpackPlugin([
 {
 from: 'td_icon.ico'
 },
 {
 from: 'src/styles/fonts',
 to: 'fonts'
 },
 {
 from: 'src/views/main-components/theme-switch/theme'
 }
 ],
  • 手机端
 new CopyWebpackPlugin([
 {
 from: 'static',
 to: 'static'
 },
 {
 from: 'src/view/component/theme-switch/theme',
 to: './css'
 }
 ])

之前我们可能已经有了这个插件了,现在只是需要把皮肤相关的css额外配置一下。以上工作完成之后已经可以动态的切换html中皮肤相关的css路径了。接下来就需要我们在需要切换css的地方引用具体的class并且写三套样式分别放在theme中的css文件里。

注意在具体的vue文件中不需要引用theme中的css,因为html中已经帮我们引用了

如果报各种与路径有关的错误那就是你的路径真的写错啦。好好对比一下组件中引用的路径,webpack中配置的路径和你的项目路径吧~

当然这只是换皮肤的一种实现思路,也就是动态切换html中的引用路径。也希望大家集思广益提供更多的解决思路~