本文将介绍CSS常见布局,常见工具方法及PC和移动端常见布局方案,另外再介绍一些CSS进阶相关面试题。
布局这一块代码示例比较多,会导致文章篇幅太长,我这里就不粘贴代码了,会给一个示例链接,点击打开一个新窗口,页面上右击打开检查(浏览器开发者工具)即可以查看布局和调试代码。
核心代码如下
css/* 水平居中核心代码(容器宽度不确定)*/
/* 方案1 */
.box1 {
width: 50%;
margin: 0 auto;
}
/* 方案2 */
.box2 {
display: table;
margin: 0 auto;
font-size: 12px;
}
/*方案三*/
.container3 {
position: relative;
}
.box3 {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
/*方案四*/
.container4 {
overflow: hidden;
}
.box4 {
float: left;
margin-left: 50%;
transform: translateX(-50%);
}
/*方案五*/
.container5 {
display: flex;
justify-content: center;
}
.box5 {
flex: none;
display: flex;
align-self: flex-start;
}
/*方案六*/
.container6 {
display: grid;
justify-content: center;
}
.box6 {
align-self: flex-start;
}
/*方案七*/
.container7 {
display: -webkit-box;
-webkit-box-pack: center;
-webkit-box-align: start;
}
文字居中的方式可以考虑用容器包裹一下,变成上面的居中布局。 本段落所讲的内容是不用标签包裹的情况如何让文字居中。
text-align: center
line-height
{display: table-cell; vertical-align: middle;}
做过移动端web或小程序开发的同学,可能会遇到过 iconfont、图标与文字(文字小于12px时)在某些android机上对不齐(尤其是三星机)
- 使用flex或inline-box+vertical-aligin 只能实现近似对齐
- 使用transform缩放,效果略微好一点,且非常烦碎
Q:为什么会对不齐?
A:简单说跟字体设计有关系,感兴趣可以读一下《Icon和文本对齐方式的探索》,接下来给的方案也是参考这种方式实现的。
html<style>
.box {
border: 1px solid red;
margin: 20px;
display: flex;
align-items: center;
line-height: 30px;
font-size: 12px;
font-family: -apple-system-font, Helvetica Neue, Arial, sans-serif;
}
.box span {
display: inline-flex;
align-items: center;
line-height: 30px;
margin: 0 6px;
}
</style>
<!--字符 \u200b 在html中使用 ​ 表示-->
<div class="box">
<span>
​
<svg t="1666104646439" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3319" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12">
<path d="M32 407.584a279.584 279.584 0 0 1 480-194.944 279.584 279.584 0 0 1 480 194.944 278.144 278.144 0 0 1-113.024 224.512L562.592 892.8a96 96 0 0 1-124.416-1.952l-308.16-270.688A278.976 278.976 0 0 1 32 407.584z" p-id="3320"></path>
</svg>
</span>
左边是iconfont, 右边是图片 三者严格居中
<span>
​
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAwhJREFUaEPtmFuoDlEUx3+nSB68eKU8uJRLXpAQuV9zj6KUEHkgp3Q68oCSB4pckkskxQMpopDLOQ8U4sEDSURIkusDUYr+pz217TPfzJ7ZM9/pq9n19X3fzFpr//9rrVlr7WmiwVdTg+OnItDVEawiUEUg0ANVCgU6MFi9ikCwCwMNpEVgLPAJ+Gw+vtv1BcYDf4HbwEdLcQkwBHgOPABe1jA60ci9B9qBb3FycQRmAfqsBHpZSveBg8CZBBYLgBZgjCNzE7gLbDfXReKc+X0Z2GtA6pL0VwODLBtvgd3AIXdvl8B64HCKm68CW4DHjtw+YFOK7g6LxFFgrSUvctOAcQk21gHH7Ps2ga3ATs8ceQWssrwmb8qrPktARWQE8NBHwZEZCLyIrkUE8hj7AqwBlmUAr32fAMMMgNPAiowkNppU7lCLCLjh9LX5B+jmK2zJTTLRmw5cz6hvp2EHgZ7Az4xGQsV3AUpZLVWqLKsTgT7AuywWCpA9bj3AwQSGx1SUAjAmmrgILMwZgZHAI/shVsNoKxuxY1+leDbQA/iVYW/1jHm2vJ6B7sAP853BVpCoGqKqiUqiOrLvGgo8dQno/y1gsq+VAuQ2mK46B7jiae+/1LFTSL/VXLZ5GipCTOXzhhlLlnsYjAUvvagP9AY06wzwMBYqEuXxaOBeirE3wBS787ry9iihsB4IReehP9dKG3uoc1XvAIudSbaTeXeYuwbM8ACRV+SEGT9sfTd9vwNngWbgd9pGLoHBgEpcvzTFHPc1A00FPsTojjLj+zPgEqDU8Vpx54FFwAUv7WxCalxqYIWuWieypNzMA2ApcD6PYppO0pGyqNJaGni7jNYiqhPQkTQvJNwvFbwPAcnMBPZYhxBfPqWD9yUguf7ASWCCB3pNiq2ADvKlr7TXKjYAdWuRmJ+ASgdugf9aOnKzQRYCESal02YH4GtzUD9VL+DRPnkISFcHcZVavQzQG4n9gEjUfeUlUHegtTasCHR1KKoIVBEI9ECVQoEODFavIhDswkADDR+Bf62LejGXewJuAAAAAElFTkSuQmCC"
style="height: 16px;">
</span>
</div>
注意事项:
<html lang="zh-CN">
,否则无法实现Icon与图片及文字之间的对齐,但是这样写也可以<html lang="en">
font-family: -apple-system-font, Helvetica Neue, Arial, sans-serif
;flex可以实现很多布局,如 居中布局、骰子布局、网格布局、百分比布局、圣杯布局、流式布局等,具体可以参考阮一峰老师的文章《Flex布局教程:实例篇》
flex布局注意事项
aligin-items
默认值为stretch
会默认拉伸项目flex-shrink
默认值是1 项目会被挤压
为什要强调这一点?应该有小伙伴跟我一样喜欢flex布局,有时重构或优化页面排版时会遇到问题,注意这两点可以提高你的效率css/*单行文本*/
.oo {
white-space:nomal;
overflow:hidden;
text-overflow:ellipsis;
}
/*多行文本*/
.muti-lines {
display: -webkit-box;
overflow: hidden;
word-break: break-all;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
浮动产生的原因
父元素的高度无法被撑开,影响与父元素同级的元素,与浮动元素同级的非浮动元素(内联元素)会跟随其后,若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面的显示。
清除浮动的几种方式
css {clear:both}
overflow
给包含浮动元素的父标签添加css属性 {overflow:auto; zoom:1; }
zoom: 1
用于兼容IE6{clear: both;}
.clearfix::after{clear: both; content: ''; display:table}
非IE浏览器scssdiv {
overflow: auto;
height: 100%;
/* 滚动条容器样式 */
&::-webkit-scrollbar {
width: 5px;
}
/* 滚动条容器样式 不包含区块 */
&::-webkit-scrollbar-track {
background-color: #f0f0f0;
}
/* 滚动条区块样式 */
&::-webkit-scrollbar-thumb {
border-radius: 2px;
background-color: #66f;
}
}
Q:CSS为什么要模块化? A:
- 1)CSS有语义化的命名约定和CSS层的分离,将有助于它的可扩展性,性能的提高和代码的组织管理。
- 2)大量的样式,覆盖、权重和很多!important, 分好层可以让团队命名统一规范,方便维护。
- 3)有责任感地去命名你的选择器。
它不是将CSS改造成编程语言,它只是加了局部作用域和模块依赖,这恰恰是网页组件最急需的功能。
具体用法,请参考阮老师的 CSS Modules用法教程,这里个人做一些总结。
import style from './style.css';
className={style.title}
:global(.title) {}
:local(.title){}
loader="localIdentName=[path][name]---[local]---[hash:base64:5]}"
.title
--> .App---title---GpMto
compose: otherClassName from './other.css';
@value blue: #0c77f8;
@value red: #f20000;
@value blue, red from './color.css';
color:red; background-color:blue;
BEM的命名规矩很容易记:block-name__element-name--modifier-name
,也就是模块名 + 元素名 + 修饰器名。
比如分页组件:
html<div class="page-btn">
<button type="button" class="page-btn__prev">上一页</button>
<!-- ... -->
<button type="button" class="page-btn__next">下一页</button>
</div>
错误的BEM命名 page-btn__list__item__link
为啥不用子代选择器来代替BEM命名?实际上BEM禁止使用子代选择器,官方给出以下理由
css/* 缩小版分页组件中,具体页码按钮隐去 */
.page-btn--min .page-btn__btn { display: none; }
.page-btn--min .page-btn__prev { width: 50%; }
.page-btn--min .page-btn__prev { width: 50%; }
is-active
、js-active
之类的类名,只用作标识,不予许有默认的公共样式。BEM可以不需要用到原子类,但是如果已经引入了类似Bootstrap的框架,也没必要强制避免使用原子类,比如pull-right
、ellipsis
、clearfix
等等类,这些类非常实用,和BEM是可以互补的。
在组件开发中其实不推荐使用原子类,因为这会降低组件的可复用性。 可复用性的最理想状态就是组件不仅仅在不同的页面中表现一致,在跨项目的情况下,也能够运行良好。 如果组件的样式因为依赖于某几个原子类就要依赖整个Bootstrap库,那么组件的迁移负担就重很多了。
原子类更适合应用在实际页面中,这是因为页面变动大而且不可复用,假设在header中,我们用到了两个组件logo和user-panel(用户操作面板),两个组件分别置于header的左侧和右侧,我们可以这么写:
html<div class="header clearfix">
<div class="logo pull-left">
<!-- ... -->
</div>
<div class="user-panel pull-left">
<!-- ... -->
</div>
</div>
header可以封装成一个模块,但它复用程度不高,不能算是组件,所以即使使用原子类也没有关系。在项目中,使用原子类之前应该考虑一下,这个场景是否变动大而且不可复用,如果是的话,我们可以放心的使用原子类。 组件应该是“自洽的”,其本身就应该构成了一个“生态圈”,也就是说,他几乎不需要外部供给,自给自足就能够运转下去。
实际页面中也应该使用BEM来避免样式冲突和覆盖
为了保证各个浏览器上样式表现一致,有以下方案:
reset.css
样式格式化,normalize.css
通过样式补充,保证各浏览器样式体验一致, 比reset.css
友好一些neat.css
normalize.css
的基础上做了些优化
核心代码如下
jsconst style = document.head.appendChild(document.createElement("style"));
window.addEventListener("resize", setRootFontSize);
if (navigator.userAgent.indexOf("Android") > -1) {
window.addEventListener("DOMContentLoaded", setRootFontSize)
}
setRootFontSize();
function setRootFontSize() {
const size = Math.max(320, Math.min(960, document.documentElement.clientWidth)) / 16;
style.innerHTML = "html{font-size: " + size + "px !important;}";
}
rem
外, 还可以用 vw
vh
实现先来了解几个概念
window.devicePixelRatio
窗口设备像素比iphone 6
手机的宽度是375px高度是667pxiphone 6
手机的屏幕物理宽度是375px 但实际宽度是 1px的距离上能放置2个像素,那么这块屏幕的逻辑像素是 750px为什么会出现物理像素和物理像素两个概念?
很久以前(pc互联网时代),
- 主流的显示器 23寸 - 19201080px - 72像素每英寸。也就是整个屏幕能显示 19201080*72 个点阵
- 从iPhone 4s 开始,乔布斯搞了个 retina 屏幕,显示器的分辨率,是 144像素每英寸。
- 假设还是之前的23寸显示器,这时候整个屏幕能显示1920108072个点阵
- 这样的原来一张图在Retina屏幕上只有72/144 = 1/2宽度和高度,这样的话导致老版本应用在Retina屏幕只用了一版的屏幕空间,这不就出bug了吗?
- 为了解决上述问题所以引入了 物理像素、逻辑像素和DPR的概念
- 物理像素:不变, 都是23寸
- 逻辑像素:老显示器是1920,则Retina屏幕显示器是1920*(72/144)
- 窗口像素比DPR:老显示器为1, Retina显示器为2
- 有了窗口像素比后, **同一张图片在不同的显示器上以逻辑像素*DPR展示,**这样这张图片新老23寸显示器上就是一样的大小了。
- 那么屏幕像素比对前端开发来说有什么影响呢?
以border: 0.5px solid red;
为例,在iphone6显示器(DPR=2)以及其他较新的显示器(DPR=2,3) 可以正常显示,在老版本显示器(DPR=1)则就不显示边框了。 最早解决1px问题还有一种方案,根据屏幕像素比检测,如果是DPR=1则用border-width:1px;
,反之border-width: 0.5px;
cssdiv {
border: 1px solid #000;
}
@media (-webkit-min-device-pixel-ratio: 2) {
div {
border: .5px solid #000;
}
}
less@mixin border1px($color: #eeeeee, $radius: 0, $style: solid, $zIndex: 1) {
position: relative;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
border: 1px $style $color;
border-radius: $radius;
transform-origin: 0 0;
transform: scale(0.5, 0.5);
box-sizing: border-box;
pointer-events: none;
z-index: $zIndex;
@content;
}
}
scss/**
0.5px 精美边框 函数
$directions 是一个数组 (T, B, R, L)
T代表top, B代表bottom, R代表right, L代表left 循序无关
$borderColor 颜色值
例子: @include myBorders((T, B));
*/
@mixin myBorders($directions, $borderColor: #eeeeee, $bg-color: #ffffff) {
$directionsMap: (
L: linear-gradient(90deg, $borderColor, $borderColor 50%, transparent 50%) bottom left no-repeat,
R: linear-gradient(270deg, $borderColor, $borderColor 50%, transparent 50%) bottom right no-repeat,
T: linear-gradient(180deg, $borderColor, $borderColor 50%, transparent 50%) top left no-repeat,
B: linear-gradient(360deg, $borderColor, $borderColor 50%, transparent 50%) bottom left no-repeat
);
$sizesMap: (
L: 1px 100%,
R: 1px 100%,
T: 100% 1px,
B: 100% 1px
);
$dirResult: ();
$sizResult: ();
@each $direction in $directions {
$dirResult: append($dirResult, map_get($directionsMap, $direction), comma);
$sizResult: append($sizResult, map_get($sizesMap, $direction), comma);
}
background: $dirResult;
background-size: $sizResult;
background-color: $bg-color;
}
css.px {
background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><line x1='0' y1='100%' x2='100%' y2='100%' stroke='red' /></svg>");
}
除此之外 1px还有一些其他解决方案 参考这里《7种方法解决移动端Retina屏幕1px边框问题》
参考 bootstrap 使用媒体查询
css
.dropdown-menu-left {
right: auto;
left: 0;
}
@media (min-width: 576px) {
.dropdown-menu-sm-left {
right: auto;
left: 0;
}
}
@media (min-width: 768px) {
.dropdown-menu-md-left {
right: auto;
left: 0;
}
}
@media (min-width: 992px) {
.dropdown-menu-lg-left {
right: auto;
left: 0;
}
}
@media (min-width: 1200px) {
.dropdown-menu-xl-left {
right: auto;
left: 0;
}
}
核心代码如下
jsconst size = 255;
const canvas = document.createElement('canvas');
canvas.setAttribute('width', `${size}px`);
canvas.setAttribute('height', `${size}px`);
const draw = canvas.getContext('2d');
draw.textAlign = 'center';
draw.textBaseline = 'middle';
draw.font = '14px Microsoft Yahei';
draw.fillStyle = 'rgba(25,25,25, 0.1)';
draw.rotate(Math.PI / 180 * -15);
draw.fillText('youremail@company.com', size/2, size/2);
const ele = document.createElement('div');
ele.setAttribute('style', `
position: fixed;top:0;right:0;left:0;bottom:0;z-index:1000;pointer-events:none;
background-image: url(${canvas.toDataURL()});background-repeat: repeat;
`);
document.body.appendChild(ele);
<label for="checkboxId">
关联 <input type="checkbox" id="checkboxId">
~
控制div的显示和隐藏核心代码
html<style>
.content {
display: none;
}
#checkboxId:checked ~ .content {
display: block;
}
</style>
<div>
<input type="checkbox" class="checkbox" id="checkboxId">
<label for="checkboxId">点我试试看</label>
<div class="content">
如果checkbox:checked 这段内容会显示
</div>
</div>
由此类推,checkbox还可以实现以下功能
border可以做三角形 梯形,波浪线 网格
简单来说CSS动画只有两种
animations + keyFrame
关键帧(逐帧)动画
transfrom
变换动画 和 transition
渐变动画
transitionend
事件实现循环具体动画的学习可以参考这篇文章《CSS实现动画的几中方式》
这里给一些案例
浏览器渲染第二帧及以后帧的过程
重排(也叫回流) --》 重绘 --》合成
本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!