Xaringan美化:CSS功夫

导读:这是Xaringan系列的第4篇,系列文章请分别参看:(系列之5)Xaringan增强:若干辅助R包及工具;(系列之4)Xaringan美化:CSS功夫;(系列之3)Xaringan效率:底层与简洁;(系列之2)Xaringan发布:blogdown网站中的展示;(系列之1)Xaringan缘起:创建课程slide

1 CSS基础

1.1 CSS selector

CSS selector
类型 含义 子类 语法 示例
Simple selector ID # #para1 { }
class/name . .center{ }
Attribute selector [ ]
Universal Selector * * { }
Grouping Selector , h1, h2, p { }
Combinator selector relationship Descendant space div p { }
Child > div > p { }
Adjacent sibling + div + p { }
General sibling ~ div ~ p { }
Pseudo -class selector state Mouse over/ visited link/focus : a:link {}
Pseudo -element selector part First letter/ line/ element :: ::first-line { }
Insert content before or after :: p::after { }

1.2 CSS layout

  • 布局:margin;border;padding

  • 位置:position: static/relative/fixed/absolute/sticky

  • 定位:top/right/bottom/left

2 Xaringan的本质

Xaringan背后是基于remark.js的。remark.js后台基本工作流程,就是采用JavaScript语言把markdown文档,映射到html上,并形成独特的slide幻灯片样式。因此,还是很有必要了解一下remark.js的说明文档(见Wiki页面)。那么Xaringan包又起到了什么作用呢?根据yihui的说法:它扩展支持了Rmarkdown语法以及R代码的直接运行!

Xaringan本质上是以html形态呈现,并使用css样式进行style视觉美化。Xaringan的技术讨论和细节见其wiki页面

归结起来这是对slide工具的一种选择,而且是选择了“未来感”的html呈现形态!那么CSS知识这是绕不过去的学习壁垒。html和css的学习至少也是需要在“三姑学院”(W3school)的汪洋里过水“捞一遍”(通读一遍)。

3 Xaringan的CSS美化

3.1 头衬和底衬(header and footer)

调整header和footer视觉效果,主要是从某个slide开始里设定layout: true,并按html语法设置header和footer样式。其完整的语法如下:

<!---slide area with layout--->
---
layout: true

<div class="my-header-h2"></div>

<div class="watermark1"></div>

<div class="watermark2"></div>

<div class="watermark3"></div>

<div class="my-footer"><span>huhuaping@  &emsp;&emsp; <a href="#chapter01"> 第01章 导论</a>
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
<a href="#sec-process">1.3 计量经济学分析过程</a> </span></div> 
---

具体样式细节包括:

  • heading文本居中设定。需要注意叠放层级参数z-index的设置。
.remark-slide-content h2, h3,h4,h5{
  position: relative;
  top: 0px;
  margin: 15px 0px 50px;
  width: 99%;
  text-shadow: 0px 0px;
  text-align: center;
  z-index: 5;
}
  • header背景色和渐变方式。
div.my-header-h2 {
    background-color: #FFFFFF;
    background: -webkit-gradient(linear, left top, right top, color-stop(0%,#f77a00), color-stop(0%,#f77a00), color-stop(10%,red), color-stop(74%,#fbd0ac), color-stop(83%,#fbd0ac), color-stop(100%,#fddfc8));
    position: fixed;
    top: 0px;
    left: 0px;
    height: 86.92913px;
    width: 100%;
}
  • footer导航样式。
div.my-footer {
    background-color: #272822;
    position: absolute;
    bottom: 0px;
    left: 0px;
    height: 20px;
    width: 100%;
}

div.my-footer span {
    font-size: 10pt;
    color: #F7F8FA;
    position: absolute;
    left: 15px;
    bottom: 2px;
}
  • footer的导航链接功能。先在css里设定链接文本的颜色,然后在slide里设定layout: true(见前面完整语句块),并按html语法设定链接定位#a-specify-id
/* link text color*/
div.my-footer a {
  color: white;
  background-color: transparent;
  text-decoration: none;
}

3.2 添加水印图片(watermark)

水印图片的个性化设定。首先需要设定css,然后在slide里设定layout: true(见前面完整语句块),并按html语法依次设定三个水印图片,其中之一如<div class="watermark1"></div>

/* water remark image */

.watermark1::after {
  content: "";
  display: block;
  width: 30%;
  height: 20%;
  position: absolute;
  top: 150px;
  left: 100px;
  background-image: url("vlog-nwsuaf.jpg");
  background-size: 80%;
  background-position: 0px 20px;
  background-repeat: no-repeat;
  opacity: 0.04;  
  /* Rotate div */
 -ms-transform: rotate(-45deg); /* IE 9 */
 -moz-transform: rotate(-45deg); /* firefox */
 -webkit-transform: rotate(-45deg); /* Chrome, Safari, Opera */
 transform: rotate(-45deg);
}

3.3 添加logo图片

方案1:手工添加logo。可以参看:a. xaringan Tip: Add A Logo to All of Your Slides。以及“队长论坛”贴文“Can I add a logo to every slide of a xaringan template using css?”。

方案2:包函数添加logoxaringanExtra::use_logo(能很好地处理logo图片,可以灵活使用class:hide_logo来指定特定slide不显示logo图片。具体请参看官方说明

xaringanExtra::use_logo(
  image_url = "https://raw.githubusercontent.com/rstudio/hex-stickers/master/PNG/xaringan.png",
  link_url = "http://slides.yihui.name/xaringan",
  position = xaringanExtra::css_position(top = "1em", right = "1em")
)

3.4 各类窗框(notes box)

在多个写作场景下(如xaringanblogdownrmarkdown),可能会用到各类提示窗框(notes box)。可以利用css设定获得个性化的提示窗框效果,具体可参看desirée de leon的博文1

基本要点:

  • 背后要用到html的div语块

  • 可以借用R包bookdownblocks代码块,进行快捷应用。

第一步:css文件(/my-css/notes-tips.css)设定如下:

/* -----------div tips------------- */

div.puzzle, div.fyi, div.demo, div.notes {
    padding: 0.5em;
    margin: 0.5em 0;
    padding-left: 100px;
    background-size: 70px;
    background-repeat: no-repeat;
    background-position: 15px center;
    min-height: 100px;
    color: #1f5386;
    background-color: #bed3ec;
    border: solid 5px #dfedff;
}

div.notes {
  background-image: url("notes-light-bulb-ff5500.png");
}

注意:需要自己手动下载背景图片,免费的图片icon下载网站有:

  • iconfinder。需要账号登陆。
  • fontawesome.com。图标可以先编辑,在下载。正文里还可使用R函数fontawesome::fa('slideshare')。例如slide图标
  • aiconica.net。搜索功能比较弱。

第二步:在.Rmd文件的yaml区域引用上面的css文件路径。

css: 
  - ../mycss/notes-tips.css

第三步:在.Rmd文件下进行写作,并引用对应的css样式:

` ``{block, type='notes', echo=T}

待完成:找到新数据,绘制一张条形图,但其不适合制作柱状图。

` ``

3.5 序贯图片的动画效果

幻灯片动画效果(animation)的背后,基本有两类思路:

第一类:小部件(partial elements)动画效果。常见的设计工具如pptx,在一张slide里面,对动画小部件(窗体、文本、箭头等)进行时序上(timeline)的安排设计,从而实现动画效果。比较适合于那些只需要利用“标准化”小部件组合形成动画的幻灯片。其优点也是显而易见的:一块幕布,持续添加小部件,比较符合动画的内容本质和视觉直觉。难点在于需要大量操作来给小部件定位(position)以及修饰小部件。

第二类,图片放映动画效果。利用人眼的视觉时间差特点,把事先设计好的系列序贯图片,连续反映展示,从而实现动画效果。比较适合于那些“手工绘制”多张序贯图片形成动画的幻灯片。其优点是:强调视觉定格(帧)关系,不太关注细节的严格一致。难点在于需要“手工绘制”,以及认为确定图片帧,小部件的细节可能会被认为并不太重要。

目前为止,直接在xaringan(或reveal.js)slide上进行第一类小部件动画制作的工具,基本上没有看到相关便利性的工具包或解决方案。xaringan(或reveal.js)slide上的动画主要是基于第二类,图片放映动画效果。例如,一个R相关会议报告做了题为Reproducible Data Workflows,就给出了“反映”型“流程图”(其实并不是流程)的动画效果,其背后就是利用序贯图片帧,不断反映,从而表现出“动画”效果。具体代码可参看其Rstudio cloud project

总体而言,在xaringan(或reveal.js)slide上主要采用“放映”型动画效果,因为动画实现(多帧图片)和动画控制(方向键)都相对简单。然而,多帧图片的设计和获得则成了其中最大难题。这样就需要依赖R之外的“绘图”工具,而且它最好还要能够自动保存序贯图片帧(反映时序中的中间环节图片)。不过很遗憾,这样的外部“绘图”工具(不管是否支持小部件)目前我是暂时没有发现(起码放狗搜了一大圈是无所得)。

不过还是找到了一个可以实现的“笨办法”。

第一阶段:绘制图片阶段。用到的主要外部工具有Powerpoint(用于绘图) 和Snagit(用于截图)。工作流程基本上是:

  1. 利用Powerpoint绘图,设计好动画。在动画窗口中控制小部件的出现先后顺序。

  2. 播放Powerpoint动画,再利用Snagit进行截图,获得图片帧,按要求进行图片自动命名(这一步很重要,方便后面调用)。需要注意在Snagit设置里,把截图质量设定为较高(File \(\Rrightarrow\) Capture perference \(\Rrightarrow\) Capture \(\Rrightarrow\) Videa Quality)

第二阶段:xaringan代码实现阶段。有了上述序贯图片,Xaringan里主要就是进行图片调用和css控制。

  1. 图片调用。因为涉及到调用系列图片(已经有规则地命名),因此可以将slide代码编程化,尽量减少代码数量,让文档结构更清晰。具体而言,需要用到的函数包括:

    • base::dir()函数调用图片路径。
    • glue:glue()函数组装slide语法要素。
    • base::cat()函数输出代码结果。
  2. CSS控制。图片相对位置等的控制,可以启用tachyons的CSS样式,具体要用到xaringanExtra包的xaringanExtra::use_tachyons()函数。

注意

  • glue::glue()函数的使用有两个坑:一是它对方括号{your parameter}敏感(默认为parameter),因此需要用双方括号嵌套,才能正确编写并识别latex代码\frac{{your code}};二是它需要双斜线\来escape特定latex语法(如)。

  • R code chunk参数一定要记得设定{r results=“asis”},这样才能实现正确代码输出(cat()函数)。

下面是Xaringan中的代码演示:

# 启用tachyons的CSS样式
xaringanExtra::use_tachyons()
# 调用图片位置
proj_slides <-sort(dir("../pic/sequence/", pattern = "quatile-min-upper-.+png$", full.names = T),decreasing = T)
# 组装slide代码要素
proj_slides_txt <- glue::glue("
## (演示)分位数计算:较小制上限插值公式(推导)

.fl.w-60[
![]({proj_slides})
]

.fl.w-40[

- 
$f_i$表示各组所对应的频次,其中
$i \\in 1,2,\\cdots,5$。
$f_{{Q_j}}$表示分位数组的频次。
$p_j$表示1/4或3/4分割位置,其中:
$p_1=\\frac{{\\sum{{f_i}}}}{{4}}$,
$p_3=\\frac{{3\\sum{{f_i}}}}{{4}}$。
]

---

")
# 输出代码结果
cat(proj_slides_txt, sep = "")

3.6 灵活选用字体

解决字体灵活选用问题。工作量理论上不是很大,主要是受到中文字体适用性和加载速度等的限制。目前暂时还不想去碰它,大众字体就大众字体,先忍一忍。具体看yihui的相关思考和说明。如思源宋体楷体

在Xaringan中给slide内容设定不同的个性化字体,基本有两种方案(当然二者结合也是可行的):

  • 方案1:个性化手动设置。首先,需要编写个性化字体CSS。然后,在yaml区域来指定调用字体CSS文件。Xaringan包的官方wiki “Deploying Your Slides Online”给出了具体操作过程和办法。此外,还有一类是集成、友好性的css工具集,也可能更便捷地提供字体设定,例如Tachyons字体库管理方案

  • 方案2:R包函数化设置。具体要用到R包xaringanthemer,其字体设置及相关R函数可参看其官方说明

上述两种方案,其关键都在于可用“字体库”(font family)。因此需要弄明白如下几个问题:

  • Xaringan默认的字体库是什么?它存放在哪里?(对于方案2的R包xaringanthemer,我们也同样需要问这样的问题。)

Xaringan字体css文件位置在:“your-pkg-dir-fonts.css”

  • 操作系统(如Win 10 或Mac OS)的字体库(system font libraries)与Xaringan的字体库是什么关系?(后者能直接调用前者的字体库么?)

  • 电脑本地渲染的slide字体,与网站开发(如netlify)上的slide字体是什么关系?(后者可能需要设置netlify的后台相关字体控制参数)。

  • 怎么来使用网络开源的字体库?slide的字体加载能否成功,以及加载速度够快么?

下面提供一些可用的免费字体库:

下面再展示一下Xaringan slide个性化字体css文件(my-font.css)的代码设定(也可参看[说明]((https://github.com/yihui/xaringan/wiki/Deploy-Slides-Online)):

# my-font.css
@import url('https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&display=swap');

body { font-family:'Songti SC', serif, 'KaiTi', '楷体','Droid Serif', 'Palatino Linotype', 'Book Antiqua', Palatino, 'Microsoft YaHei' ; }

h1, h2, h3 {
  font-family: 'Ma Shan Zheng', cursive,'楷体';
  font-weight: normal;
}

注意

  • 字体使用有先后顺序。客户浏览器会根据操作系统字体情况,依次按顺序来加载字体。

  • 综合考虑不同平台和设备下的字体可用性。因此,往往需要设定字体库的“备胎计划”(fallback)。

此外,Xaringan中不同内容要素(elements)的字体应该考虑不同的设定,具体内容要素类别包括:

  • 标题(headings):h1,h2,h3,h4,...

  • 代码区域(code chunk)以及行内代码(inline code):.remark-code.remark-inline-code

  • 表格(table):表题(caption),表注(notation)。

  • 图片(figture):图题(caption),图注(notation)。

  • 数学公式符号(latex equation and symbol):

4 下一步需要处理的CSS问题

4.1 储备炫酷技能

提前准备好各类丰富slide功能的css实现方法。具体明确的一些炫酷功能,相关slide和css样板可以参看:

4.2 图文混排

图文混排技巧。

  • remark.js自带光环的边栏效果(side bar).left-column[]或者.right-column[]

  • remark.js自带光环的两栏效果(two columns).pull-left[]或者.pull-right[]

4.3 Todo清单

  • 页面布局。页面紧凑度和宽松度灵活调整。例如remark-slide-content.roomy

  • 前导符设定。正文符号列表的前导符设定问题。

  • 播放动画效果。常见的进入或退出等动画效果。CSS可以参考相对比较成熟的Animate.css,可以直接拿来就用。

  • 窗格动画效果。大抵类似于PowerPoint的动画窗格设计,目前在Xaringan或remark.js里还没有看到。可以参看Earo Wang’s slide。以及另一个很不错的Xaringan slide报告题为Reproducible Data Workflows给出了绘制版流程图的动画效果,其背后的关键是连续的png部件是如何分解得到的(可参看其Rstudio cloud project)。有待进一步去找这样的draw工具,它应该能自动保存中间环节的png。

基于CSS的窗格动画Build your own universe。相关资源可以参看:Garrick Aden‑Buie的网站

5 Tachyons CSS

因为使用R包xaringanExtra的缘故,初次接触到Tachyons。简单地,Tachyons是一套创新的CSS架构理念和工具。

该CSS架构的可能最初设想,是来自前端开发员Adam Morse的一篇倡议性短文CSS and Scalability(他的个人首页)。然后经过实践探索和迭代坚持,诞生了目前的Tachyons工具集。具体的介绍可以参看 Learn Tachyons。如果要使用各种css元件和样式,也可以登陆快速检索入口:Cheat Sheet

这里主要说两个与本人项目相关的话题。

第一个话题是:为什么要尝试选择Tachyons的CSS架构理念。其实也就是Tachyons要解决的主要CSS痛点。个人认为最重要的优点有:1)坚持“所见即所得”。下面的图既是最好的说明。具体而言,它坚持明确的“语义化代码”,让CSS显性化,实现人类友好。2)坚持“乐高组装模块化”。基于最小颗粒的CSS原件和风格,可以进行无限可能的模块化组合,从而实现CSS代码可复用性和稳定性,以及维护的简单化。3)坚持“函数化CSS开发”。与R语言类似的函数化编程思维一致,可以通过参数进行灵活控制。例如其中提到的“尺度化”(scale)概念,运用于字体大小(fontsize)、宽度(width)等。个人感觉类似于ggplot2的数据化映射思路。

tachons

before

第二个话题是:如何将Tachyons的CSS架构运用于Xaringan的视觉输出设计中去?当然目前已经可以基于xaringanExtra包进行引入,但是里面也还有很多需要有效衔接的地方。

6 最后的若干思考和感受

这次对Xaringan 又一次发起冲锋,直接缘由是《计量经济学》双一流课程团队的视频录制。团队里其他人都不用R和Rmarkdown,更不要提Xaringan slide了。大家仍旧还是基于PowerPoint准备和制作授课幻灯片,有的老师甚至操作系统还是win7,office套件还是2010版!所以只能我事先用powerpoint设定好ppt模板,大家各自拿去制作自己的授课ppt(其实大部分团队老师甚至连ppt母版也不会用)。考虑到我自己的实际需求,我是希望能同时兼顾自己使用xaringan 和团队其他老师使用ppt的一致性——当然是不能奢求最后两者视觉效果的完全一样!目前在Xaringan上的设定调整,基本上达到了ppt模板类似效果的80%左右。

事实上,Xaringan和ppt二者效果一致性的达成,并不是最大的挑战。基本上基于html的Xaringan slide,可以使用css技巧实现ppt里的几乎所有功能。而况Xaringan还有很多ppt无法实现的“现代的”以及“未来的”诸多功能!真正的挑战在于团队协作,尤其是对于非常技术守旧的团队(并不指技术之外的其他方面)。到此,我的基本态度就是:最低限度地在技术方面与其他人协作,重点是把协作任务下自己事情做完、基本ok即可!

当然,这里面也还有一个在协作冲突中推动自己不断学习进步的问题。显然,如果没有这次的协作录制课程,我肯定还是会一如往常地坚持“最小化学习”策略:也即如无实际所需,绝不去茫然学习所谓的各种知识技能。这一次,我充分认识到了CSS对于Xaringan甚至对于Html的重要性,并且看到了一些文档协作、协作和输出的“未来”趋势和走向!

Related