最近在用vue仿网易云UI实现一个简单的音乐台项目。在写到歌单的时候卡住了一段时间,发现网易云的UI设计挺高级的(对我来说),于是花时间研究了一下。先来看下网易云官方ui效果。
网易云歌单.gif
可以看到不同歌单进入时,歌单的背景色是不同的,因为看上去像是纯色的背景,所以我一开始的思路是提取封面的主色调作背景色,就去参考了不少提取主色的算法。提取出来后发现并没有达到想要的效果(背景不是主色调)。有提取图片色调这方面需求的可以参考一下。
算法:提取图片主色调
CSS高斯模糊
寻找其它解决方案的过程中发现很多人提到css高斯模糊,结合伪类能够实现这种效果。于是就尝试了一下,发现确实可以。下面是我的具体实现(单独的测试页面)。
html
fas fa-arrow-left
歌单
class="d_img"
src="https://picsum.photos/414/736?random"
width="120px"
height="120px"
/>
css高斯模糊栀子花-
通过css高斯模糊,结合伪类能够实现网易云歌单ui效果
暂无数据!
html中有一个class为"d_bg"的空div标签,这个标签是专门用来放背景图片的,不做它用。(在"d_wrapper"元素下,与"d_head"即内容元素为兄弟元素)。
设置父元素相对定位
.d_wrapper{
position: relative; /*设置相对定位*/
overflow: hidden;
height: 15rem;
}
设置背景图片
.d_bg{
background: url("https://picsum.photos/414/736?random"); /*背景图片*/
background-repeat: no-repeat;
background-size: cover; /*适应容器*/
background-position: 50%; /*调整图片位置*/
transform: scale(1.5); /*图片放大*/
filter: blur(20px); /*高斯模糊*/
height: 15rem; /*设置背景高度*/
}
给图片div容器及伪元素:before设置绝对定位
.d_bg,
.d_bg:before{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
设置伪元素
.d_bg:before{
content: " "; /*伪类必须设置content属性才会生效*/
background-color: rgba(0, 0, 0, 0.25); /*设置蒙层,兜底*/
}
要使伪类样式生效必须设置content属性,即使为空。
兜底策略:当样式设置完成之后,实际测试中发现一个问题,就是背景上方的图片文字是白色,而当背景图片加载不出来或者整个背景图片大部分是白色时,此时会导致上方内容白色文字看不见。所以会有一个兜底策略,就是给伪类:before设置一个灰色背景色(rgba设置透明度),这样即使背景图片模糊出来是白色的,也会叠加上一层灰色背景。
实现效果
高斯模糊效果.PNG
到这里背景高斯模糊的效果已经实现了,不过网易云歌单在上滑的时候会发现歌单内容元素会慢慢变成透明,而标题栏背景色逐渐加深并且会出现边框。这里我尝试了一下发现要让标题栏变色会比较复杂(不知道有没有大佬知道简单点的实现方法),所以最后我的实现就只是把内容元素变成透明。代码:
export default {
data () {
return {
// 初始距离标题栏高度
originalTop: ''
}
},
methods: {
// 监听滚动条改变透明度
handleScroll () {
this.$nextTick(() => {
// 根据滚动距离设置透明度
let top = document.querySelector('.d_body').getBoundingClientRect().top
document.querySelector('.d_head').style.opacity = (top - 48) / this.originalTop
})
}
},
mounted () {
// 滚动条复位
document.documentElement.scrollTop = 0
// 获取初始距离标题栏高度(标题栏固定48px)
this.originalTop = document.querySelector('.d_body').getBoundingClientRect().top - 48
window.addEventListener('scroll', this.handleScroll, true)
},
beforeDestroy () {
window.removeEventListener('scroll', this.handleScroll, true)
}
}
实现效果
实现效果.gif
仿网易云.gif
完整代码
fas fa-arrow-left
歌单
class="d_img"
src="https://picsum.photos/414/736?random"
width="120px"
height="120px"
/>
css高斯模糊栀子花-
通过css高斯模糊,结合伪类能够实现网易云歌单ui效果
暂无数据!
export default {
data () {
return {
// 初始距离标题栏高度
originalTop: ''
}
},
methods: {
// 监听滚动条设置透明度
handleScroll () {
this.$nextTick(() => {
// 根据滚动距离设置透明度
let top = document.querySelector('.d_body').getBoundingClientRect().top
document.querySelector('.d_head').style.opacity = (top - 48) / this.originalTop
})
}
},
mounted () {
// 滚动条复位
document.documentElement.scrollTop = 0
// 获取初始距离标题栏高度
this.originalTop = document.querySelector('.d_body').getBoundingClientRect().top - 48
window.addEventListener('scroll', this.handleScroll, true)
},
beforeDestroy () {
window.removeEventListener('scroll', this.handleScroll, true)
}
}
.nav_bar{
height: 3rem;
position: fixed;
color: white;
font-size: 1.2rem;
padding: 0.5rem 1rem;
z-index: 2; /*设置层级 */
}
/* 设置父元素 */
.d_wrapper{
position: relative;
overflow: hidden;
height: 15rem;
}
.d_head{
display: flex;
padding: 1rem;
margin: 2rem 0 0 1rem;
font-size: 1.2rem;
z-index: 1; /* 设置层级 */
position: relative; /* 设置定位保持最高层,保证改变opacity时层级不会发生变化 */
}
.d_bg{
background: url("https://picsum.photos/414/736?random"); /*背景图片*/
background-repeat: no-repeat;
background-size: cover; /*适应容器*/
background-position: 50%; /*调整图片位置*/
transform: scale(1.5); /*图片放大*/
filter: blur(20px); /*高斯模糊*/
height: 15rem; /*设置背景高度*/
}
.d_bg,
.d_bg:before{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.d_bg:before{
content: " "; /*伪类必须设置content属性才会生效*/
background-color: rgba(0, 0, 0, 0.25); /*设置蒙层,兜底*/
}
.d_icon{
margin-right: 1rem;
}
.d_img{
border-radius: 0.5rem; /* 图片圆角 */
z-index: 1;
}
/* 描述内容样式 flex布局 */
.d_content{
color: white;
display: flex;
flex-direction: column;
justify-content: space-around;
width: 60%;
margin-left: 1rem;
z-index: 1;
}
.d_title{
font-size: 1.4rem;
}
.d_subtitle,.d_desc{
font-size: 1rem;
}
.d_body{
position: relative;
height: 43rem;
overflow: auto;
margin-top: -2rem;
background-color: white;
border-top-left-radius: 1.5rem;
border-top-right-radius: 1.5rem;
text-align: center;
}
.d_list{
margin-top: 16rem;
}
chrome调试为iphone6 plus,虽然最后实现的效果和网易云官方的还差不少,但是自己觉得还算过得去,哈哈😆。
我用的ui框架是vuetify,Material Design设计风格,蛮喜欢的,自己写移动端经常用整个。如果存在不对的地方或者有更好的设计方案欢迎大家留言指正哦。