用CSS画一个QQ音乐图标

主要用到了relative定位、border的垂直和水平分量,之所以用区块遮盖实现内凹,因为radial-gradient我不太熟悉。

<head>
    <style>
         :root {
            --color: rgb(68, 202, 68);
        }
        
        .div {
            width: 240px;
            height: 240px;
            border-radius: 120px;
            background-color: rgb(235, 227, 128);
        }
        
        .music {
            --vertical: 40px;
            --horizontal: 50px;
            width: 100px;
            height: 80px;
            background: var(--color);
            border-bottom-left-radius: var(--horizontal) var(--vertical);
            border-bottom-right-radius: var(--horizontal) var(--vertical);
            border-top-left-radius: var(--horizontal) var(--vertical);
            border-top-right-radius: var(--horizontal) var(--vertical);
            position: relative;
            top: calc(100% - 90px);
            left: calc((100% - 100px)/2);
        }
        
        .pole {
            height: 170px;
            width: 10px;
            background: var(--color);
            position: relative;
            left: 52px;
            bottom: 120px;
            border: 10px;
            transform: rotate(-27deg);
        }
        
        .flag {
            width: 80px;
            height: 40px;
            background-color: var(--color);
            border-bottom-right-radius: 60px 35px;
        }
        
        .block {
            background: rgb(235, 227, 128);
            width: 80px;
            height: 20px;
            border-bottom-left-radius: 70px 20px;
            position: relative;
            bottom: 1px
        }
    </style>
</head>

<body>
    <div class="div">
        <div class="music">
            <div class="pole">
                <div class="flag">
                    <div class="block"></div>
                </div>
            </div>
        </div>

    </div>
</body>

CSS Functions && CSS Variables

CSS Variables

Syntax

{
--variable:#ffffff;
color: var(--variable);
}

CSS Functions

calc()

calc()用于对数值作计算,单位包括长宽(px、vw等)、频率(Hz等)、角度(deg、rad、turn等)、时间(s、ms)、小数和整数。

calc()要求+和-的左右有空格。

例如,width:calc(100% - 30px)定义了比父元素宽度小30px的宽度。

attr()

attr()用于取回被选择元素的属性,比如对一个<img>标签,可以用attr(src)获取图片地址。如果css选择器选择了多个元素,attr()在每个元素上可能有不同结果。

max()

取最大值。

min()

取最小值。

fit-content()

fit-content()接受一个参数,如果这个参数超过可设置的最大值,那么用最大值替代,如果小于最小值,则用最小值替代。原理其实是min(maximum size, max(minimum size, argument))。

env()

env()的作用类似于var(),但env()除了返回值,还会改变user agent-defined环境变量的值,MDN有如下例子:

body {
  padding:
    env(safe-area-inset-top, 20px)
    env(safe-area-inset-right, 20px)
    env(safe-area-inset-bottom, 20px)
    env(safe-area-inset-left, 20px);
}

第二个参数是可以省略的,这样不会更改user agent-defined环境变量的值。

user agent stylesheet即浏览器默认样式表,比如<h1></h1>会自带margin。有时这会给开发和适配带来不便,解决方案是使用reset.css。

counter()

MDN示例,看完应该明白了:

HTML

<ol>
  <li></li>
  <li></li>
  <li></li>
</ol>

CSS

ol {
  counter-reset: listCounter;/**重置计数器**/
}
li {
  counter-increment: listCounter;/**每多一个li元素listCounter+1**/
}
li::after {
  content: "[" counter(listCounter) "] == [" counter(listCounter, upper-roman) "]";/**通过counter获取listCounter的值**/
}

RESULT

linear-gradient()

线性渐变图像,支持设置颜色、角度、位置(百分比位置),例如:

background: linear-gradient(0.5turn, #e66465 0%, #9198e5 100%);

repeat()、minmax()

和Grid配合使用,详情参考CSS Grid

rotate()、matrix()、scale()、translate()、skew()等

旋转、矩阵表达的线性变换、缩放、移动、扭曲,详情参考CSS transform

opacity()、blur()等

透明、模糊,详情参考CSS filter

一些实验特性

element()

比如background:element(#id)可以以#id选择的元素为背景,element()使元素作为图片使用。仅Firefox支持。

结合LeanCloud做一个查询术语的单页应用

前言

计算机领域中存在大量的术语,如果恰好是自己未接触的领域,看到一连串不懂的英文缩写,一定是一件令人困惑的事。虽然有百度和谷歌等搜索引擎,如果我们能自建一个更专业的数据库,似乎对我们有很大帮助(可玩性很高)。

一些问题

虽然该项目看起来只是查询数据库,但实际开发过程中遇到了比较多的一些问题。梳理这些问题是有一定价值的,不仅能避免以后被困扰,而且能加深我对这个领域的认识。

与LeanCloud数据存储交互

最初知道LeanCloud,其实是有朋友的hexo博客下留有评论框,静态博客下的评论框引起了我的好奇,F12表明服务提供商是LeanCloud,我猜测它是以专门为app、网站等应用提供后端服务为生。

LeanCloud使用难度不算大,官方文档也还行,但我找了半天才找到我想要的查询数据库的方法和实例。

建立对SDK的引用对象

官方来源:https://leancloud.cn/docs/sdk_setup-js.html

var AV = require("leancloud-storage");
var { Query, User } = AV;
var APP_ID = "**Hidden**";
var APP_KEY = "**Hidden**";

AV.init({
  appId: APP_ID,
  appKey: APP_KEY
});

查询数据示例

这里演示了在Terms表中查找attr==某个值的记录,result是一个数组。

var query = new AV.Query("Terms");
    query.equalTo("attr", value);//选出 attr列的值 为value 的行
    //find以为还有first等方法,都返回promise对象
    query.find().then(res => {
      ...
    }).catch(err => {
        ...
    });

(补充)添加数据示例

该示例将在TestObject表新建一条words='Hello World!'的记录。

var TestObject = AV.Object.extend('TestObject');
var testObject = new TestObject();
testObject.save({
  words: 'Hello World!'
}).then(function(object) {
  alert('LeanCloud Rocks!');

监听全局键盘事件

这个单页应用实际由两个状态组成,一个状态显示搜索框,另一个状态显示结果/详情,我们想实现搜索框聚焦时按下enter切换到详情组件很简单,但反过来就有点麻烦,因为详情组件不支持聚焦。

在网页中,只有聚焦的元素才能监听键盘事件(聪明的你也一定观察到了),同时事件冒泡的方向是自下向上,综合这两点,我们有两个方向。第一个方向是通过tabindex属性使详情组件支持聚焦,第二个方向是直接向顶级元素添加键盘监听器。除了搜索组件与详情组件,网页还有导航栏与底部,如果失去焦点就不能通过快捷键返回,这不是我们想要的效果。

我们通过向document添加事件处理实现在详情状态下按esc返回搜索状态(position用来控制状态,keyCode==27的键正是esc):

    document.onkeydown = e => {
      if (this.position == true && e.keyCode == 27) {
        this.position = false;
      }
    };

Vue-cli与Vue-router结合

Vue-router的官方文档给出了cdn接入的示例,我们这里介绍结合Vue-cli使用。

首先,在项目根目录下npm i vue-router

然后,在main.js里导入(import VueRouter from 'vue-router')并注册到Vue(Vue.use(VueRouter))

再新建一个VueRouter实例:

const router = new VueRouter({
    routes: [
            { path: '/detail', component: Detail },
            { path: '/', component: SearchBox }
        ] 
})

修改一下Vue根实例:

new Vue({
    render: h => h(App),
    router
}).$mount('#app')

剩下的部分则是将<router-link>标签与<router-view>标签添加到需要使用的地方。

布局与CSS选择器

Layout

Bootstrap-vue的布局很方便,通过b-row与b-col节点上的align-v与align-self属性可以实现对齐效果。对于col内部的行内元素对齐,我使用了verticle-align属性,通常设置bottom。

vh

对于整页布局,除了传统的对html,body,div设置100%高度,还有一种方法,就是为div设置100vh的高度,该应用中我为导航栏与底部标签各设置了5vh的高度,内容区域高度90vh,刚好占满了浏览器可视区域。这么做存在的问题是对移动设备兼容性不佳,如果要适配移动设备,可以借助媒体查询断点使用其他方式布局移动端。

自动聚焦与$refs与Vue的生命周期

其实$refs我一直没怎么使用过,最大的问题是我不能从$refs获取的节点中得到很多html结点信息,修改结点属性时,不如直接用querySelector。但这里实现自动聚焦却很实用,代码如下:

 <b-form-input ref="focusThis" @keyup.enter="$emit('match',keyword)" v-model="keyword" list="my-list-id"/>
mounted(){
     this.$refs.focusThis.focus()
  }

为什么说生命周期?我以前习惯在create钩子里进行初始化操作,但create时结点还未渲染,我不得不把聚焦操作放到mounted钩子。

DEMO

https://demo.guohere.com/term-search/

数据库暂时只有两条记录'html'与'css',请用这两个条目试验。支持快捷键enter(匹配)与esc(返回)。

css常用单位

px

pixel像素点,最常用的单位

%

percent百分比,经常用到

em

element,1em等于元素字体的尺寸

rem

rem=root element,rem等于根元素字体的尺寸

vw

viewport width,可视区域宽度的1%

vh

viewport height,可视区域高度的1%

vmin

vw与vh中较小的那一个作为单位

vmax

vw与vh中较大的那一个作为单位

较不常用的单位

cm:centimetre厘米

mm:millimeter毫米

pt:points(12pt=16px)

pc:picas(1pc=12pt)

in:inch(1in=96px)

ch:1ch="0"的宽度

ex:1ex=当前字体的x-height

用webfont为你的网站添加图标

有些网站的图标不存在对应的图片文件,也并非通过js画图,它们的CSS长这样:

h2::before{

content:'\e942'

}

实际上e942是这个字符的16进制unicode编码,在unicode编码中,E000-F8FF是用户自定义区,形状可以任意制定。如果我们向网站引入自定义后的字体,就可以用上面的方式显示图标了。

css引入webfont:

@font-face {

font-family:;/**相当于变量名,可以自己定义,如果元素中的font-family对应这里,@font-face为这些元素定义了字体族,他们将使用src定义的字体**/

src:;/**使用的字体,可以是local("font名称")或者url("url地址"),支持多个来源**/

}

@font-face还可以为不同格式、不同字重的文字匹配字体,也可以为特定字符匹配特定字体,想了解更多可以参考:

https://developer.mozilla.org/zh-CN/docs/Web/CSS/@font-face

那么,到哪里去生成自定义字体呢?下面推荐3个相关网站:

IcoMoon App
Ionicons: The premium icon font for Ionic Framework
Fontello - icon fonts generator

想了解更多关于css插入图标的细节,参阅:

https://www.cnblogs.com/zccst/p/3655069.html

CSS一个div内两个子元素的高度自适应

3-1-2019更新:使用flex布局,align-items:flex-start即可。


设想这样一个情况:一个父元素有两个子元素,父元素的高度不确定,用子元素撑起来

但是这会导致一个问题:各个子元素的高度不一致,为子元素添加height:100%是无效的。这种方式需要父元素高度确定,然而父元素的高度由子元素确定。

猜想渲染时由于父元素高度不确定,会计算出各个子元素的高度再确定父元素高度,但计算子元素高度时并没有父元素高度可以参考,因此上述方法行不通。

你可以

为父元素设置固定高度

配合height:100%,两个子元素都能撑满父元素

利用span元素与布局

如果span的定位是absolute类型,那么它的高度可以等于父元素的高度。父元素只根据相对定位的子元素决定高度,也就是说,absolute定位的span设置height:100%是有效的,父元素的高度对它来说是已知的。

这种方法需要避免span元素与其他元素重合,需要留出span的位置,将span放到位置上。

这种方法下,父元素的高度仍然由最高的相对定位的子元素确定,其它元素放到span中,所以需要知道最高的子元素。

使用同色背景

虽然很简单,却很实用的方法。子元素的高度虽然不都是100%,但效果一样。

Pseudo elements伪元素与Pseudo classes伪类

伪类和伪元素用于css选择器,利用他们使css更灵活。

常见的伪元素

::after

::after用于描述处于css渲染层的一个伪元素,相当于选中元素的最后一个子元素,但这个元素与DOM节点无关,位于选择的元素之后,伪元素的内容用content属性描述。

::before

与after相对应,相当于被选中元素的第一个子元素。

::selection

将用户选择的内容作为伪元素。

::first-letter

选中第一个字符作为伪元素。但只能用于块级元素,并且第一个字符前不能有图片或内联表格。

::first-line

选中第一行作为伪元素,只能用于块级元素(行内元素也用不着这个说法...)。

(更多…)