360 AI音箱官网开发手记

695 阅读12分钟
原文链接: mp.weixin.qq.com

奇技指南

今天(4月2日),360集团董事长兼CEO周鸿祎宣布,AI音箱MAX正式现货首销!!!音质超棒的360 AI音箱,它的官网颜值自然也不能低,今天来看看360 AI音箱官网是如何开发滴~

本文首发于公众号“奇舞周刊”,作者李松峰,资深技术图书译者,翻译出版过40余部技术及交互设计专著,现任360奇舞团高级前端开发工程师,360前端技术委员会委员、W3C AC代表

3月28号,老周在他的IoT发布会上,发布了360 AI音箱MAX,今天,这款音箱正式开售啦!

作为圈内骨灰级音频发烧友的周鸿祎表示,这款产品由他亲自调音,音质杠杠滴。

价格感人,优惠价现在只要199,感兴趣的小伙伴请到文末有优惠方式呦~

言归正传,我们来讲点技术的事,今天由李老师为大家介绍360 AI音箱官网开发手记。

官网地址:http://speaker.360.cn/

360 AI音箱官网开发手记

标题说的是官网,但实际上本文主要介绍的是展示大图的页面,也就是概述页。为简便起见,本文以下用“官网”代称“360 AI音箱官网概述页”。

这次官网的设计稿是提前4天才开始出的,最后一个页面是上线前一天下午2点给的。总之,时间非常紧,没有充裕的时间去调研多种实现方案。开发中采用了比较保守、兼容性好的技术。

基本数据

说到大图,就得知道主流显示器的分辨率。京东在销显示器的分辨率如下:

  • 3840×2160

  • 3840×1080

  • 3440×1440

  • 2560×1440

  • 2560×1080

  • 1920×1200

  • 1920×1080

维基百科2019年1月调查结果如下(https://p4.ssl.qhimg.com/t01fff3464ffc757200.png):

标准 比例 宽度(px) 高度(px) 用户(%)
nHD 16:9 640 360 4.26
VGA 4:3 800 600 0.42
XGA 4:3 1024 768 3.29
WXGA 16:9 1280 720 3.15
WXGA 16:10 1280 800 3.88
SXGA 5:4 1280 1024 3.37
HD ~16:9 1360 768 1.65
HD ~16:9 1366 768 24.27
WXGA+ 16:10 1440 900 6.55
非标 16:9 1536 864 5.5
HD+ 16:9 1600 900 4.81
WSXGA+ 16:10 1680 1050 2.52
FHD 16:9 1920 1080 19.20
WUXGA 16:10 1920 1200 1.20
QWXGA 16:9 2048 1152 0.46
非标 21:9 2560 1080 n/a
QHD 16:9 2560 1440 2.09
21:9 3440 1440 n/a
4K UHD 16:9 3840 2160 n/a

也就是说,2560像素及以下宽度屏幕的用户占86%以上。为此,官网所有大图最大宽度为2560像素。

图片数 25
大图数 15
页面体积 6.8MB

接下来,本文主要从以下几方面概述官网开发涉及的技术点:

  • 呈现大图

  • 弹性文字

  • HTML结构

  • CSS布局

  • 自定义字体

  • 固定页脚

呈现大图:img?background-image?

为简单起见,我们将整个页面的开发分成几个部分。首先从大图的呈现说起。

img标签可以直接把包裹它的元素撑起来,并且能在浏览器窗口缩放时保持宽高比同步缩放。

background-image因为是背景图片,所以需要明确设置包裹元素的宽度和高度,才能在浏览器窗口缩放时不至于少显示图片。而且,即使使用了 background-size: cover,也需要额外通过媒体查询在某个断点重新设置包裹元素的宽度和高度,以保持元素与图片具有相同的宽高比。

出于快速开发的目的,我们选择了使用img标签:

<figure class="full-img">

<img src="https://p1.ssl.qhimg.com/t01f061f44107fd8ed1.jpg">

</figure>

如下图所示:

弹性文字:rem?em?

大图页需要适应屏幕缩放同步缩放文字大小。因此,需要在使用rem和 em单位间做出选择。

rem是根元素 html的font-size值,而 em则是body元素的 font-size值。使用这两个单位都可以实现对应文字大小的全局性缩放。区别在于,rem是全局性唯一参照大小,直接修改 html的font-size就可以全局缩放文字大小;而 em单位基于从父元素继承的大小缩放,只能通过缩放父元素的font-size来修改页面局部的继承大小。

为此我们决定使用简单直接的rem。 首先,根据设计稿确定某个屏幕宽度下对应的html的 font-size值。比如,大约1200像素时,对应的rem为100像素(之所以设置为100像素,是为了换算方便):

html {

  font-size: 100px;

  body {

    font-size: .16rem;

    min-width: 1226px;

    background-color: #ffffff;

    font-family: sans-serif;

  }

}

然后再设定一个缩放系数,比如12,通过JavaScript来根据浏览器窗口大小动态修改rem大小。我们定义了一个模块ajust_rem.js,导出 adjustRemOnResize类:

import throttle from 'lodash.throttle'

export default class adjustRemOnResize {

  constructor ({divisor, remBaseSize}) {

    this.divisor = divisor

    this.remBaseSize = remBaseSize

    this.html = $('html')

    this.resize()

    $(window).on('resize', throttle(this.resize.bind(this), 300))

  }

  resize () {

    const currentWidth = $(window).width()

    const remDyncSize = currentWidth / this.divisor

    const fontSize = remDyncSize < this.remBaseSize ? this.remBaseSize : remDyncSize

    this.html.css({fontSize})

  }

}

在相应页面引入这个类,传入参数,创建实例:

import adjustRemOnResize from './ajust_rem.js'

const adjustRemOnResizeOptions = {

  divisor: 12,

  remBaseSize: 100

}

new adjustRemOnResize(adjustRemOnResizeOptions)

remBaseSize其实就是最小 rem值。从前面的代码可知,当浏览器窗口宽度为1200像素时,除以12就是100像素。相应地,当浏览器窗口宽度为2400像素时,除以12,rem就是200像素。

而所有尺寸(文字大小、内外边距、定位偏移等)需要根据窗口大小动态改变的值,都使用类似如下的方式来声明:

small {

  font-size: .12rem;

}

.double-engine {

  h2 {

    margin-bottom: 0.2rem;

  }

  figure {

    margin-top: 0.6rem;

  }

}

比如,small标签中的文本大小在 rem为100像素时为12px:

而在rem为200像素时则会变成 24px:

HTML结构

分别确定了处理大图和文字的方式,接下来更进一步,处理二者结合在一起的情况。换句话说,就是要把文字定位到大图上面,此时的HTML结构如下:

<section>

  <article>

    <h3>囊括三大音乐平台资源,千万音乐随心畅听</h3>

    <p>目前已经接入腾讯音乐集团旗下酷狗音乐,QQ音乐、酷我音乐接入中,囊括市场排名前三音乐平台,千万音乐随心畅听。</p>

    <small>* 部分音乐服务需要登录对应账号后才能享用免费服务,免费服务有效期1年,有效期结束后服务方式以官方公告为准</small>

  </article>

  <figure>

    <img src="https://p4.ssl.qhimg.com/t010b8bdd20c5668ae4.png">

  </figure>

</section>

其中,每个section代表音箱的一个卖点,卖点要通过大图和文字来展现:

  • article:文字区

  • h3:标题

  • p:内容

  • small:说明

  • figure:大图区

  • img:大图

CSS布局

基于上一节的HTML结构,CSS技术使用了最为保守、兼容性最好的定位和行内块居中。

首先,来看一下定位技术的运用:

section {

  position: relative;

  article {

    position: absolute;

    p {

      text-align: justify;

    }

  }

  figure {

    width: 100%;

    margin-top: 0.2rem;

    img {

      width: 100%;

    }

  }

}

如前所述,包含卖点的section默认自然是一个块级元素,它的直接子元素只有两个: article和figure。这里的CSS把 section设置为相对定位,为其子元素创建一个定位上下文。而通过把article设置为绝对定位,就可以实现将其移出正常布局流同时又相对于其定位上下文 section定位的目的。

figure呢?自然还包含在 section内部,并且其包含的img通过引用大图,并将宽度设置为 100%,最终会将整个figure乃至 section撑至满屏。

这样,对于包含卖点的article通过设置百分比单位的 left属性和width值,就可以将文字相对于大图任意定位,比如“儿童模式”的HTML:

<li class="child-mode">

  <section>

   <article class="intro-left intro7">

    <h3>专属儿童模式<br>精选内容助力成长</h3>

    <p>内容运营团队针对不同年龄段儿童,精选定制化的音频内容与百科知识库,提供科学的儿童内容。

    <br>云端建立儿童内容黑名单,屏蔽不适合小朋友收听的音乐与音频内容,避免受到不良内容的伤害。</p>

    <figure><img src="https://p5.ssl.qhimg.com/t017963a80a701e29ba.png"></figure>

   </article>

  <figure class="full-img">

    <img src="https://p5.ssl.qhimg.com/t0172cdc426c2f437c3.jpg">

  </figure>

 </section>

</li>

CSS如下:

.intro-left {

  left: 19%;

}

.child-mode {

  .intro7 {

    top: 1.2rem;

    width: 26%;

    h2 {

      margin: 0.1rem 0;

    }

    figure {

      width: 100%;

      margin-top: 0.2rem;

      img {

        width: 100%;

      }

    }

  }

}

除了使用绝对定位将文字定位到任意位置,还有一个通用需求是把文字定位在页面/大图水平中间。

这时候,我们使用了传统的display: inline-block;技术,即把包含文字的块级元素变成行内块,而在其父级通过 text-align将其居中:

<article class="middle-heading-position-top intro6">

  <div>

    <h2>双重智能引擎<br>大人孩子都喜欢</h2>

    <p>双重智能唤醒,内置两套独立唤醒词与应答语音,可以温柔贴心,也可以稚气天真。<br>儿童专属童声语音,节奏更轻缓,语调活泼,更符合小朋友的沟通习惯。</p>

  </div>

</article>

CSS:

.middle-heading-position-top {

    text-align: center;

    width: 100%;

    div {

      display: inline-block;

    }

}

注意,无论是使用定位,还是居中行内块,都要恰当配合百分比单位的使用。

自定义字体

官网需要使用多种不同字重的思源黑体。这正是奇字库派上用场的地方,只要在模板包含文件里加上如下script代码:

奇字库是360内部自建的针对版权和开源字体一个字体托管和动态截取服务,使用基于Web Font Loader(由Goolge和Adobe联合开发)定制的Web字体加载脚本,可以一键式向网页中引入自定义Web字体。

<script>

(function(d) {

  var config = {

    fontFamily: ['siyuan-regular', 'siyuan-normal'],

    fontHash: ['/*siyuan-regular-hash*/', '/*siyuan-normal-hash*/'],

    urlType: 'data',

    scriptTimeout: 3000,

    async: true,

  },

  // ……省略加载脚本……

})(document);

</script>

就可以在CSS里像使用本地字体一样使用自定义字体了:

.wf-siyuanregular-n4-active .feature-list h2 {

  font-family: siyuan-regular, sans-serif;

}

.wf-siyuannormal-n4-active .feature-list p,

.wf-siyuannormal-n4-active .feature-list small {

  font-family: siyuan-normal, sans-serif;

}

固定页脚

“让该死的页脚始终呆在页面底部”是所有页面的共同需求。推荐一下纯CSS解决方案:

* {

 box-sizing: border-box;

}

*:before,

*:after {

 box-sizing: border-box;

}

html,

body {

 height: 100%;

 position: relative;

}

.main-container {

 min-height: 100vh; /* 与视口同高 */

 overflow: hidden;

 display: block;

 position: relative;

 padding-bottom: 100px; /* 控制页脚高度 */

}

footer {

 position: absolute;

 bottom: 0;

 width: 100%;

}

这个方案的优点:

  • 纯CSS,无JavaScript

  • 适用于所有支持视口单位(vh)的浏览器

唯一的缺点:

  • 需要通过容器元素的padding-bottom控制页脚的实际高度

感谢作者 @zero(https://medium.com/@zerox)。

小 结

由于时间紧,官网没有采用Flexbox等比较先进的技术,而是选择了保守但兼容性好的定位和行内块居中技术,当然别忘了在父级和子级配合使用百分比宽度。另外,由于有了奇字库(360内部字体托管和截取服务),让使用自定义Web字体也变得非常简单。本文最后还顺便推荐了一个解决页脚始终显示在底部的纯CSS方案。

下面是福利放送时间~

界世的你当不

只做你的肩膀

 360官方技术公众号 

技术干货|一手资讯|精彩活动

空·