“等风来不如追风去,追逐的过程就是人生的意义”。
借朋友吉言,“2018在头条,2019成为头条”,这就是我2019的目标,我已经在追风的路上。你呢?不要停下脚步,继续前行吧。
今天来个实用的小知识,看下图:
CSS3径向渐变实现优惠券波浪造型
很多人看到左右的波浪边框,第一想法,应该是用图片实现。现在我们就打破这一想法,用CSS搞定这个效果。
radial-gradient() 函数用径向渐变创建 "图像"。径向渐变由中心点定义。为了创建径向渐变你必须设置两个终止色。
语法: background: radial-gradient(shape size at position, start-color, ..., last-color);
CSS3径向渐变实现优惠券波浪造型
<div class="coupon"></div>
这里用radial-gradient绘制一个圆,设置left为1px,top为8px,形成半圆。
.coupon { position: relative; width: 400px; height: 160px; margin: 50px auto; background-image: radial-gradient( circle at 1px 8px, transparent 6px, #ff9e6d 6px, #ff9e6d 0px); }
CSS3径向渐变实现优惠券波浪造型
看看原本是这样,这里的left是8px
.coupon { ... background-image: radial-gradient( circle at 8px 8px, transparent 6px, #ff9e6d 6px, #ff9e6d 0px); ... }
CSS3径向渐变实现优惠券波浪造型
设置背景大小,y轴默认平铺,x轴不允许平铺,形成多个半圆,造就波浪造型。
.coupon { ... background-image: radial-gradient( circle at 1px 8px, transparent 6px, #ff9e6d 6px, #ff9e6d 0px); background-size: 200px 18px; background-repeat-x: no-repeat; ... }
CSS3径向渐变实现优惠券波浪造型
同理,我们添加右边波浪,
.coupon { ... background-image: radial-gradient( circle at 1px 8px, transparent 6px, #ff9e6d 6px, #ff9e6d 0px), radial-gradient( circle at 199px 8px, transparent 6px, #ff9e6d 6px, #ff9e6d 0px); background-size: 200px 18px; background-position: 0 0, 200px 0; background-repeat-x: no-repeat; }
CSS3径向渐变实现优惠券波浪造型
<div class="coupon">50元</div>
用:before伪类,制作中间的虚线,:after伪类,添加“立即领取”文字。同时添加金额(50元)样式。
.coupon { ... font-size: 60px; color: #fff; font-weight: bold; line-height: 160px; padding-left: 60px; box-sizing: border-box; cursor: pointer; } .coupon::before { position: absolute; content: ""; left: 240px; top: 0; bottom: 0; width: 0; border-left: 1px dashed #fff; } .coupon::after { position: absolute; content: "立即领取"; font-size: 26px; width: 70px; top: 50%; right: 2%; transform: translate(-50%, -50%); line-height: 40px; letter-spacing: 5px; }
CSS3径向渐变实现优惠券波浪造型
演示地址:CSS3径向渐变实现优惠券波浪造型
CSS3 box-shadow实现背景动画
从浅到深的学习 CSS3阴影(box-shadow)
CSS3线性渐变、阴影、缩放实现动画下雨效果
下文章来源于GoUpUp ,作者dj
go-app是一个使用 Go + WebAssembly 技术编写渐进式 Web 应用的库。WebAssembly 是一种可以运行在现代浏览器中的新式代码。近两年来,WebAssembly 技术取得了较大的发展。我们现在已经可以使用 C/C++/Rust/Go 等高级语言编写 WebAssembly 代码。本来就来介绍go-app这个可以方便地使用 Go 语言来编写 WebAssembly 代码的库。
go-app对 Go 语言版本有较高的要求(Go 1.14+),而且必须使用Go module。先创建一个目录并初始化Go Module(Win10 + Git Bash):
$ mkdir go-app && cd go-app
$ go mod init
然后下载安装go-app包:
$ go get -u -v github.com/maxence-charriere/go-app/v6
至于Go module的详细使用,去看煎鱼大佬的Go Modules 终极入门。
首先,我们要编写 WebAssembly 程序:
package main
import "github.com/maxence-charriere/go-app/v6/pkg/app"
type Greeting struct {
app.Compo
name string
}
func (g *Greeting) Render() app.UI {
return app.Div().Body(
app.Main().Body(
app.H1().Body(
app.Text("Hello, "),
app.If(g.name != "",
app.Text(g.name),
).Else(
app.Text("World"),
),
),
),
app.Input().
Value(g.name).
Placeholder("What is your name?").
AutoFocus(true).
OnChange(g.OnInputChange),
)
}
func (g *Greeting) OnInputChange(src app.Value, e app.Event) {
g.name = src.Get("value").String()
g.Update()
}
func main() {
app.Route("/", &Greeting{})
app.Run()
}
在go-app中使用组件来划分功能模块,每个组件结构中必须内嵌app.Compo。组件要实现Render()方法,在需要显示该组件时会调用此方法返回显示的页面。go-app使用声明式语法,完全使用 Go 就可以编写 HTML 页面,上面绘制 HTML 的部分比较好理解。上面代码中还实现了一个输入框的功能,并为它添加了一个监听器。每当输入框内容有修改,OnInputChange方法就会调用,g.Update()会使该组件重新渲染显示。
最后将该组件挂载到路径/上。
编写 WebAssembly 程序之后,需要使用交叉编译的方式将它编译为.wasm文件:
$ GOARCH=wasm GOOS=js go build -o app.wasm
如果编译出现错误,使用go version命令检查 Go 是否是 1.14 或更新的版本。
接下来,我们需要编写一个 Go Web 程序使用这个app.wasm:
package main
import (
"log"
"net/http"
"github.com/maxence-charriere/go-app/v6/pkg/app"
)
func main() {
h := &app.Handler{
Title: "Go-App",
Author: "dj",
}
if err := http.ListenAndServe(":8080", h); err != nil {
log.Fatal(err)
}
}
go-app提供了一个app.Handler结构,它会自动查找同目录下的app.wasm(这也是为什么将目标文件设置为app.wasm的原因)。然后我们将前面编译生成的app.wasm放到同一目录下,执行该程序:
$ go run main.go
默认显示"Hello World":
在输入框中输入内容之后,显示会随之变化:
可以看到,go-app为我们设置了一些基本的样式,网页图标等。
GitHub 上这张图很好地说明了 HTTP 请求的执行流程:
用户请求先到app.Handler层,它会去app.wasm中执行相关的路由逻辑、去磁盘上查找静态文件。响应经由app.Handler中转返回给用户。用户就看到了app.wasm渲染的页面。实际上,在本文中我们只需要编写一个 Go Web 程序,每次编写新的 WebAssembly 之后,将新编译生成的 app.wasm 文件拷贝到 Go Web 目录下重新运行程序即可。注意,如果页面未能及时刷新,可能是缓存导致的,可尝试清理浏览器缓存。
自定义一个组件很简单,只需要将app.Compo内嵌到结构中即可。实现Render()方法可定义组件的外观,实际上app.Compo有一个默认的外观,我们可以这样来查看:
func main() {
app.Route("/app", &app.Compo{})
app.Run()
}
编译生成app.wasm之后,一开始的 Go Web 程序不需要修改,直接运行,打开浏览器查看:
在快速开始中,我们还介绍了如何使用事件。使用声明式语法app.Input().OnChange(handler)即可监听内容变化。事件处理函数必须为func (src app.Value, e app.Event)类型,app.Value是触发对象,app.Event是事件的内容。通过app.Value我们可以得到输入框内容、选择框的选项等信息,通过app.Event可以得到事件的信息,是鼠标事件、键盘事件还是其它事件:
type ShowSelect struct {
app.Compo
option string
}
func (s *ShowSelect) Render() app.UI {
return app.Div().Body(
app.Main().Body(
app.H1().Body(
app.If(s.option == "",
app.Text("Please select!"),
).Else(
app.Text("You've selected "+s.option),
),
),
),
app.Select().Body(
app.Option().Body(
app.Text("apple"),
),
app.Option().Body(
app.Text("orange"),
),
app.Option().Body(
app.Text("banana"),
),
).
OnChange(s.OnSelectChange),
)
}
func (s *ShowSelect) OnSelectChange(src app.Value, e app.Event) {
s.option = src.Get("value").String()
s.Update()
}
func main() {
app.Route("/", &ShowSelect{})
app.Run()
}
上面代码显示一个选择框,当选项改变时上面显示的文字会做相应的改变。初始时:
选择后:
组件可以嵌套使用,即在一个组件中使用另一个组件。渲染时将内部的组件表现为外部组件的一部分:
type Greeting struct {
app.Compo
}
func (g *Greeting) Render() app.UI {
return app.P().Body(
app.Text("Hello, "),
&Name{name: "dj"},
)
}
type Name struct {
app.Compo
name string
}
func (n *Name) Render() app.UI {
return app.Text(n.name)
}
func main() {
app.Route("/", &Greeting{})
app.Run()
}
上面代码在组件Greeting中内嵌了一个Name组件,运行显示:
go-app提供了组件的 3 个生命周期的钩子函数:
例如:
type Foo struct {
app.Compo
}
func (*Foo) Render() app.UI {
return app.P().Body(
app.Text("Hello World"),
)
}
func (*Foo) OnMount() {
fmt.Println("component mounted")
}
func (*Foo) OnNav(u *url.URL) {
fmt.Println("component navigated:", u)
}
func (*Foo) OnDismount() {
fmt.Println("component dismounted")
}
func main() {
app.Route("/", &Foo{})
app.Run()
}
编译运行,在浏览器中打开页面,打开浏览器控制台观察输出:
component mounted
component navigated: http://localhost:8080/
在前面的例子中我们已经看到了如何使用声明式语法编写 HTML 页面。go-app为所有标准的 HTML 元素都提供了相关的类型。创建这些对象的方法名也比较好记,就是元素名的首字母大写。如app.Div()创建一个div元素,app.P()创建一个p元素,app.H1()创建一个h1元素等等。在go-app中,这些结构都是暴露出对应的接口供开发者使用的,如div对应HTMLDiv接口:
type HTMLDiv interface {
Body(nodes ...Node) HTMLDiv
Class(v string) HTMLDiv
ID(v string) HTMLDiv
Style(k, v string) HTMLDiv
OnClick(h EventHandler) HTMLDiv
OnKeyPress(h EventHandler) HTMLDiv
OnMouseOver(h EventHandler) HTMLDiv
}
可以看到每个方法都返回该HTMLDiv自身,所以支持链式调用。调用这些方法可以设置元素的各方面属性:
和设置事件监听:
例如下面代码:
app.Div().Body(
app.H1().Body(
app.Text("Title"),
),
app.P().ID("id").
Class("content").Body(
app.Text("something interesting"),
),
)
相当于 HTML 代码:
<div>
<h1>title</h1>
<p id="id" class="content">
something interesting
</p>
</div>
我们可以在app.Raw()中直接写 HTML 代码,app.Raw()会生成对应的app.UI返回:
svg := app.Raw(`
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
`)
但是这种写法是不安全的,因为没有检查 HTML 的结构。
我们在最开始的例子中就已经用到了条件语句,条件语句对应 3 个方法:If()/ElseIf()/Else()。
If和ElseIf接收两个参数,第一个参数为bool值。如果为true,则显示第二个参数(类型为app.UI),否则不显示。
Else必须在If或ElseIf后使用,如果前面的条件都不满足,则显示传入Else方法的app.UI:
type ScoreUI struct {
app.Compo
score int
}
func (c *ScoreUI) Render() app.UI {
return app.Div().Body(
app.If(c.score >= 90,
app.H1().
Style("color", "green").
Body(
app.Text("Good!"),
),
).ElseIf(c.score >= 60,
app.H1().
Style("color", "orange").
Body(
app.Text("Pass!"),
),
).Else(
app.H1().
Style("color", "red").
Body(
app.Text("fail!"),
),
),
app.Input().
Value(c.score).
Placeholder("Input your score?").
AutoFocus(true).
OnChange(c.OnInputChange),
)
}
func (c *ScoreUI) OnInputChange(src app.Value, e app.Event) {
score, _ := strconv.ParseUint(src.Get("value").String(), 10, 32)
c.score = int(score)
c.Update()
}
func main() {
app.Route("/", &ScoreUI{})
app.Run()
}
上面我们根据输入的分数显示对应的文字,90及以上显示绿色的Good!,60-90之间显示橙色的Pass!,小于60显示红色的Fail!。下面是运行结果:
假设我们要编写一个 HTML 列表,当前有一个字符串的切片。如果一个个写就太繁琐了,而且不够灵活,且容易出错。这时就可以使用Range()方法了:
type RangeUI struct {
app.Compo
name string
}
func (*RangeUI) Render() app.UI {
langs := []string{"Go", "JavaScript", "Python", "C"}
return app.Ul().Body(
app.Range(langs).Slice(func(i int) app.UI {
return app.Li().Body(
app.Text(langs[i]),
)
}),
)
}
func main() {
app.Route("/", &RangeUI{})
app.Run()
}
Range()可以对切片或map中每一项生成一个app.UI,然后平铺在某个元素的Body()方法中。
运行结果:
在go-app中,我们可以很方便的自定义右键弹出的菜单,并且为菜单项编写响应:
type ContextMenuUI struct {
app.Compo
name string
}
func (c *ContextMenuUI) Render() app.UI {
return app.Div().Body(
app.Text("Hello, World"),
).OnContextMenu(c.OnContextMenu)
}
func (*ContextMenuUI) OnContextMenu(src app.Value, event app.Event) {
event.PreventDefault()
app.NewContextMenu(
app.MenuItem().
Label("item 1").
OnClick(func(src app.Value, e app.Event) {
fmt.Println("item 1 clicked")
}),
app.MenuItem().Separator(),
app.MenuItem().
Label("item 2").
OnClick(func(src app.Value, e app.Event) {
fmt.Println("item 2 clicked")
}),
)
}
func main() {
app.Route("/", &ContextMenuUI{})
app.Run()
}
我们在OnContextMenu中调用了event.PreventDefault()阻止默认菜单的弹出。看运行结果:
点击菜单项,观察控制台输出~
上面我们都是使用go-app内置的app.Handler处理客户端的请求。我们只设置了简单的两个属性Author和Title。app.Handler还有其它很多字段可以定制:
type Handler struct {
Author string
BackgroundColor string
CacheableResources []string
Description string
Env Environment
Icon Icon
Keywords []string
LoadingLabel string
Name string
RawHeaders []string
RootDir string
Scripts []string
ShortName string
Styles []string
ThemeColor string
Title string
UseMinimalDefaultStyles bool
Version string
}
CSS 和 JS 文件必须在app.Handler中声明。下面是一个示例app.Handler:
h := &app.Handler{
Name: "Luck",
Author: "Maxence Charriere",
Description: "Lottery numbers generator.",
Icon: app.Icon{
Default: "/web/icon.png",
},
Keywords: []string{
"EuroMillions",
"MEGA Millions",
"Powerball",
},
ThemeColor: "#000000",
BackgroundColor: "#000000",
Styles: []string{
"/web/luck.css",
},
Version: "wIKiverSiON",
}
本文中 WebAssembly 代码都在各自的目录中。Go Web 演示代码在 web 目录中。先进入某个目录,使用下面的命令编译:
$ GOARCH=wasm GOOS=js go build -o app.wasm
然后将生成的app.wasm拷贝到web目录:
$ cp app.wasm ../web/
切换到 web 目录,启动服务器:
$ cd ../web/
$ go run main.go
本文介绍如何使用go-app编写基于 WebAssembly 的 Web 应用程序。可能有人会觉得,go-app编写 HTML 的方式有点繁琐。但是我们可以写一个转换程序将普通的 HTML 代码转为go-app代码,感兴趣可以自己实现一下。WebAssembly 技术非常值得关注一波~
属性解释
background属性是css中应用比较多,且比较重要的一个属性,它是负责给盒子设置背景图片和背景颜色的,background是一个复合属性,它可以分解成如下几个设置项:
background-color 设置背景颜色
background-image 设置背景图片地址
background-repeat 设置背景图片如何重复平铺
background-position 设置背景图片的位置
background-attachment 设置背景图片是固定还是随着页面滚动条滚动
实际应用中,我们可以用background属性将上面所有的设置项放在一起,而且也建议这么做,这样做性能更高,而且兼容性更好,比如:“background: #00FF00 url(bgimage.gif) no-repeat left center fixed”,这里面的“#00ff00”是设置background-color;“url(bgimage.gif)”是设置background-image;“no-repeat”是设置background-repeat;“left center”是设置background-position;“fixed”是设置background-attachment,各个设置项用空格隔开,有的设置项不写也是可以的,它会使用默认值。
举例:
下面这些例子使用下面这张图片做为背景图:
1、“background:url(bg.jpg)”,默认设置一个图片地址,图片会从盒子的左上角开始将盒子铺满。
2、“background:cyan url(bg.jpg) repeat-x”,横向平铺盒子,盒子其他部分显示背景颜色“cyan”。
3、“background:cyan url(bg.jpg) repeat-y”,纵向平铺盒子,盒子其他部分显示背景颜色“cyan”。
4、“background:cyan url(bg.jpg) no-repeat”,背景不重复,背景和盒子左上角对齐,盒子其他部分显示背景颜色“cyan”。
5、“background:cyan url(bg.jpg) no-repeat left center”,背景不重复,背景和盒子左中对齐,盒子其他部分显示背景颜色“cyan”。
6、“background:cyan url(bg.jpg) no-repeat right center”,背景不重复,背景和盒子右中对齐,也就是背景图片的右边对齐盒子的右边,盒子其他部分显示背景颜色“cyan”。
相关代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test background</title> <style type="text/css"> .backshow{ width:320px; height:160px; border:3px solid #333; float:left; margin:10px; } .bg1{background:cyan url(bg.jpg);} .bg2{background:cyan url(bg.jpg) repeat-x;} .bg3{background:cyan url(bg.jpg) repeat-y;} .bg4{background:cyan url(bg.jpg) no-repeat;} .bg5{background:cyan url(bg.jpg) no-repeat left center;} .bg6{background:cyan url(bg.jpg) no-repeat right center;} </style> </head> <body> <div class="backshow bg1"></div> <div class="backshow bg2"></div> <div class="backshow bg3"></div> <div class="backshow bg4"></div> <div class="backshow bg5"></div> <div class="backshow bg6"></div> </body> </html>
例子说明:
background-position的设置,可以在水平方向设置“left”、“center”、“right”,在垂直方向设置“top”、“center”、“bottom”,除了设置这些方位词之外,还可以设置具体的数值。
比如说,我们想把下边的盒子用右边的图片作为背景,并且让背景显示图片中靠近底部的那朵花:
用上面中间那张图片作为左边那个比它尺寸小的盒子的背景,上面右边的实现效果设置为:“background:url(location_bg.jpg) -110px -150px”,第一个数值表示背景图相对于自己的左上角向左偏移110px,负值向左,正值向右,第二个数值表示背景图相对于自己的左上角向上偏移150px,负值向上,正值向下。
实现原理示意图:
对应代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test background</title> <style type="text/css"> .backshow{ width:320px; height:160px; border:3px solid #333; float:left; margin:10px; } .bg{width:94px; height:94px; border:3px solid #666; background:url(location_bg.jpg) -110px -150px; } </style> </head> <body> <div class="bg"></div> </body> </html>
理解练习:
通过雪碧图制作如下布局:
*请认真填写需求信息,我们会在24小时内与您取得联系。