922 lines
1.7 MiB
HTML
922 lines
1.7 MiB
HTML
|
<!DOCTYPE html>
|
|||
|
|
|||
|
<html>
|
|||
|
|
|||
|
<head>
|
|||
|
|
|||
|
<meta charset="utf-8" />
|
|||
|
<meta name="generator" content="pandoc" />
|
|||
|
<meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
|
|||
|
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|||
|
|
|||
|
<meta name="author" content="Carson Sievert" />
|
|||
|
|
|||
|
<meta name="date" content="2024-03-15" />
|
|||
|
|
|||
|
<title>Overview of the sass R package</title>
|
|||
|
|
|||
|
<script>// Pandoc 2.9 adds attributes on both header and div. We remove the former (to
|
|||
|
// be compatible with the behavior of Pandoc < 2.8).
|
|||
|
document.addEventListener('DOMContentLoaded', function(e) {
|
|||
|
var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
|
|||
|
var i, h, a;
|
|||
|
for (i = 0; i < hs.length; i++) {
|
|||
|
h = hs[i];
|
|||
|
if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
|
|||
|
a = h.attributes;
|
|||
|
while (a.length > 0) h.removeAttribute(a[0].name);
|
|||
|
}
|
|||
|
});
|
|||
|
</script>
|
|||
|
|
|||
|
<style type="text/css">
|
|||
|
code{white-space: pre-wrap;}
|
|||
|
span.smallcaps{font-variant: small-caps;}
|
|||
|
span.underline{text-decoration: underline;}
|
|||
|
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
|||
|
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
|||
|
ul.task-list{list-style: none;}
|
|||
|
</style>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<style type="text/css">
|
|||
|
code {
|
|||
|
white-space: pre;
|
|||
|
}
|
|||
|
.sourceCode {
|
|||
|
overflow: visible;
|
|||
|
}
|
|||
|
</style>
|
|||
|
<style type="text/css" data-origin="pandoc">
|
|||
|
pre > code.sourceCode { white-space: pre; position: relative; }
|
|||
|
pre > code.sourceCode > span { line-height: 1.25; }
|
|||
|
pre > code.sourceCode > span:empty { height: 1.2em; }
|
|||
|
.sourceCode { overflow: visible; }
|
|||
|
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
|||
|
div.sourceCode { margin: 1em 0; }
|
|||
|
pre.sourceCode { margin: 0; }
|
|||
|
@media screen {
|
|||
|
div.sourceCode { overflow: auto; }
|
|||
|
}
|
|||
|
@media print {
|
|||
|
pre > code.sourceCode { white-space: pre-wrap; }
|
|||
|
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
|||
|
}
|
|||
|
pre.numberSource code
|
|||
|
{ counter-reset: source-line 0; }
|
|||
|
pre.numberSource code > span
|
|||
|
{ position: relative; left: -4em; counter-increment: source-line; }
|
|||
|
pre.numberSource code > span > a:first-child::before
|
|||
|
{ content: counter(source-line);
|
|||
|
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
|||
|
border: none; display: inline-block;
|
|||
|
-webkit-touch-callout: none; -webkit-user-select: none;
|
|||
|
-khtml-user-select: none; -moz-user-select: none;
|
|||
|
-ms-user-select: none; user-select: none;
|
|||
|
padding: 0 4px; width: 4em;
|
|||
|
color: #aaaaaa;
|
|||
|
}
|
|||
|
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
|||
|
div.sourceCode
|
|||
|
{ }
|
|||
|
@media screen {
|
|||
|
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
|||
|
}
|
|||
|
code span.al { color: #ff0000; font-weight: bold; }
|
|||
|
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; }
|
|||
|
code span.at { color: #7d9029; }
|
|||
|
code span.bn { color: #40a070; }
|
|||
|
code span.bu { color: #008000; }
|
|||
|
code span.cf { color: #007020; font-weight: bold; }
|
|||
|
code span.ch { color: #4070a0; }
|
|||
|
code span.cn { color: #880000; }
|
|||
|
code span.co { color: #60a0b0; font-style: italic; }
|
|||
|
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; }
|
|||
|
code span.do { color: #ba2121; font-style: italic; }
|
|||
|
code span.dt { color: #902000; }
|
|||
|
code span.dv { color: #40a070; }
|
|||
|
code span.er { color: #ff0000; font-weight: bold; }
|
|||
|
code span.ex { }
|
|||
|
code span.fl { color: #40a070; }
|
|||
|
code span.fu { color: #06287e; }
|
|||
|
code span.im { color: #008000; font-weight: bold; }
|
|||
|
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; }
|
|||
|
code span.kw { color: #007020; font-weight: bold; }
|
|||
|
code span.op { color: #666666; }
|
|||
|
code span.ot { color: #007020; }
|
|||
|
code span.pp { color: #bc7a00; }
|
|||
|
code span.sc { color: #4070a0; }
|
|||
|
code span.ss { color: #bb6688; }
|
|||
|
code span.st { color: #4070a0; }
|
|||
|
code span.va { color: #19177c; }
|
|||
|
code span.vs { color: #4070a0; }
|
|||
|
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; }
|
|||
|
</style>
|
|||
|
<script>
|
|||
|
// apply pandoc div.sourceCode style to pre.sourceCode instead
|
|||
|
(function() {
|
|||
|
var sheets = document.styleSheets;
|
|||
|
for (var i = 0; i < sheets.length; i++) {
|
|||
|
if (sheets[i].ownerNode.dataset["origin"] !== "pandoc") continue;
|
|||
|
try { var rules = sheets[i].cssRules; } catch (e) { continue; }
|
|||
|
var j = 0;
|
|||
|
while (j < rules.length) {
|
|||
|
var rule = rules[j];
|
|||
|
// check if there is a div.sourceCode rule
|
|||
|
if (rule.type !== rule.STYLE_RULE || rule.selectorText !== "div.sourceCode") {
|
|||
|
j++;
|
|||
|
continue;
|
|||
|
}
|
|||
|
var style = rule.style.cssText;
|
|||
|
// check if color or background-color is set
|
|||
|
if (rule.style.color === '' && rule.style.backgroundColor === '') {
|
|||
|
j++;
|
|||
|
continue;
|
|||
|
}
|
|||
|
// replace div.sourceCode by a pre.sourceCode rule
|
|||
|
sheets[i].deleteRule(j);
|
|||
|
sheets[i].insertRule('pre.sourceCode{' + style + '}', j);
|
|||
|
}
|
|||
|
}
|
|||
|
})();
|
|||
|
</script>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<style type="text/css">body {
|
|||
|
background-color: #fff;
|
|||
|
margin: 1em auto;
|
|||
|
max-width: 700px;
|
|||
|
overflow: visible;
|
|||
|
padding-left: 2em;
|
|||
|
padding-right: 2em;
|
|||
|
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|||
|
font-size: 14px;
|
|||
|
line-height: 1.35;
|
|||
|
}
|
|||
|
#TOC {
|
|||
|
clear: both;
|
|||
|
margin: 0 0 10px 10px;
|
|||
|
padding: 4px;
|
|||
|
width: 400px;
|
|||
|
border: 1px solid #CCCCCC;
|
|||
|
border-radius: 5px;
|
|||
|
background-color: #f6f6f6;
|
|||
|
font-size: 13px;
|
|||
|
line-height: 1.3;
|
|||
|
}
|
|||
|
#TOC .toctitle {
|
|||
|
font-weight: bold;
|
|||
|
font-size: 15px;
|
|||
|
margin-left: 5px;
|
|||
|
}
|
|||
|
#TOC ul {
|
|||
|
padding-left: 40px;
|
|||
|
margin-left: -1.5em;
|
|||
|
margin-top: 5px;
|
|||
|
margin-bottom: 5px;
|
|||
|
}
|
|||
|
#TOC ul ul {
|
|||
|
margin-left: -2em;
|
|||
|
}
|
|||
|
#TOC li {
|
|||
|
line-height: 16px;
|
|||
|
}
|
|||
|
table {
|
|||
|
margin: 1em auto;
|
|||
|
border-width: 1px;
|
|||
|
border-color: #DDDDDD;
|
|||
|
border-style: outset;
|
|||
|
border-collapse: collapse;
|
|||
|
}
|
|||
|
table th {
|
|||
|
border-width: 2px;
|
|||
|
padding: 5px;
|
|||
|
border-style: inset;
|
|||
|
}
|
|||
|
table td {
|
|||
|
border-width: 1px;
|
|||
|
border-style: inset;
|
|||
|
line-height: 18px;
|
|||
|
padding: 5px 5px;
|
|||
|
}
|
|||
|
table, table th, table td {
|
|||
|
border-left-style: none;
|
|||
|
border-right-style: none;
|
|||
|
}
|
|||
|
table thead, table tr.even {
|
|||
|
background-color: #f7f7f7;
|
|||
|
}
|
|||
|
p {
|
|||
|
margin: 0.5em 0;
|
|||
|
}
|
|||
|
blockquote {
|
|||
|
background-color: #f6f6f6;
|
|||
|
padding: 0.25em 0.75em;
|
|||
|
}
|
|||
|
hr {
|
|||
|
border-style: solid;
|
|||
|
border: none;
|
|||
|
border-top: 1px solid #777;
|
|||
|
margin: 28px 0;
|
|||
|
}
|
|||
|
dl {
|
|||
|
margin-left: 0;
|
|||
|
}
|
|||
|
dl dd {
|
|||
|
margin-bottom: 13px;
|
|||
|
margin-left: 13px;
|
|||
|
}
|
|||
|
dl dt {
|
|||
|
font-weight: bold;
|
|||
|
}
|
|||
|
ul {
|
|||
|
margin-top: 0;
|
|||
|
}
|
|||
|
ul li {
|
|||
|
list-style: circle outside;
|
|||
|
}
|
|||
|
ul ul {
|
|||
|
margin-bottom: 0;
|
|||
|
}
|
|||
|
pre, code {
|
|||
|
background-color: #f7f7f7;
|
|||
|
border-radius: 3px;
|
|||
|
color: #333;
|
|||
|
white-space: pre-wrap;
|
|||
|
}
|
|||
|
pre {
|
|||
|
border-radius: 3px;
|
|||
|
margin: 5px 0px 10px 0px;
|
|||
|
padding: 10px;
|
|||
|
}
|
|||
|
pre:not([class]) {
|
|||
|
background-color: #f7f7f7;
|
|||
|
}
|
|||
|
code {
|
|||
|
font-family: Consolas, Monaco, 'Courier New', monospace;
|
|||
|
font-size: 85%;
|
|||
|
}
|
|||
|
p > code, li > code {
|
|||
|
padding: 2px 0px;
|
|||
|
}
|
|||
|
div.figure {
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
img {
|
|||
|
background-color: #FFFFFF;
|
|||
|
padding: 2px;
|
|||
|
border: 1px solid #DDDDDD;
|
|||
|
border-radius: 3px;
|
|||
|
border: 1px solid #CCCCCC;
|
|||
|
margin: 0 5px;
|
|||
|
}
|
|||
|
h1 {
|
|||
|
margin-top: 0;
|
|||
|
font-size: 35px;
|
|||
|
line-height: 40px;
|
|||
|
}
|
|||
|
h2 {
|
|||
|
border-bottom: 4px solid #f7f7f7;
|
|||
|
padding-top: 10px;
|
|||
|
padding-bottom: 2px;
|
|||
|
font-size: 145%;
|
|||
|
}
|
|||
|
h3 {
|
|||
|
border-bottom: 2px solid #f7f7f7;
|
|||
|
padding-top: 10px;
|
|||
|
font-size: 120%;
|
|||
|
}
|
|||
|
h4 {
|
|||
|
border-bottom: 1px solid #f7f7f7;
|
|||
|
margin-left: 8px;
|
|||
|
font-size: 105%;
|
|||
|
}
|
|||
|
h5, h6 {
|
|||
|
border-bottom: 1px solid #ccc;
|
|||
|
font-size: 105%;
|
|||
|
}
|
|||
|
a {
|
|||
|
color: #0033dd;
|
|||
|
text-decoration: none;
|
|||
|
}
|
|||
|
a:hover {
|
|||
|
color: #6666ff; }
|
|||
|
a:visited {
|
|||
|
color: #800080; }
|
|||
|
a:visited:hover {
|
|||
|
color: #BB00BB; }
|
|||
|
a[href^="http:"] {
|
|||
|
text-decoration: underline; }
|
|||
|
a[href^="https:"] {
|
|||
|
text-decoration: underline; }
|
|||
|
|
|||
|
code > span.kw { color: #555; font-weight: bold; }
|
|||
|
code > span.dt { color: #902000; }
|
|||
|
code > span.dv { color: #40a070; }
|
|||
|
code > span.bn { color: #d14; }
|
|||
|
code > span.fl { color: #d14; }
|
|||
|
code > span.ch { color: #d14; }
|
|||
|
code > span.st { color: #d14; }
|
|||
|
code > span.co { color: #888888; font-style: italic; }
|
|||
|
code > span.ot { color: #007020; }
|
|||
|
code > span.al { color: #ff0000; font-weight: bold; }
|
|||
|
code > span.fu { color: #900; font-weight: bold; }
|
|||
|
code > span.er { color: #a61717; background-color: #e3d2d2; }
|
|||
|
</style>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</head>
|
|||
|
|
|||
|
<body>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<h1 class="title toc-ignore">Overview of the sass R package</h1>
|
|||
|
<h4 class="author">Carson Sievert</h4>
|
|||
|
<h4 class="date">2024-03-15</h4>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<style>
|
|||
|
pre {
|
|||
|
border: 1px solid #eee;
|
|||
|
}
|
|||
|
pre.r {
|
|||
|
background-color: #ffffff;
|
|||
|
margin-bottom: -0.5em;
|
|||
|
}
|
|||
|
pre.r code {
|
|||
|
background-color: #ffffff;
|
|||
|
}
|
|||
|
pre.css {
|
|||
|
background-color: #f8f8f8;
|
|||
|
border-radius: 0;
|
|||
|
border-bottom-left-radius: 4px;
|
|||
|
border-bottom-right-radius: 4px;
|
|||
|
}
|
|||
|
</style>
|
|||
|
<div id="why" class="section level2">
|
|||
|
<h2>Why Sass?</h2>
|
|||
|
<p><a href="https://sass-lang.com/">Sass</a> is the most widely used,
|
|||
|
feature rich, and stable CSS extension language available. It has become
|
|||
|
an essential tool in modern web development because of its ability to
|
|||
|
<em>reduce complexity</em> and <em>increase composability</em> when
|
|||
|
styling a website. For a basic example, suppose you want to use the same
|
|||
|
color for multiple styling rules in your website (e.g., hyperlinks and
|
|||
|
buttons). With CSS, you’d have to repeat that color every time it is
|
|||
|
used in styling rule, so in a large project, changing at a later point
|
|||
|
can be tedious and error-prone.</p>
|
|||
|
<div class="sourceCode" id="cb1"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb1-1"><a href="#cb1-1" tabindex="-1"></a>a {</span>
|
|||
|
<span id="cb1-2"><a href="#cb1-2" tabindex="-1"></a> <span class="kw">color</span><span class="ch">:</span> <span class="cn">salmon</span><span class="op">;</span></span>
|
|||
|
<span id="cb1-3"><a href="#cb1-3" tabindex="-1"></a>}</span>
|
|||
|
<span id="cb1-4"><a href="#cb1-4" tabindex="-1"></a>button {</span>
|
|||
|
<span id="cb1-5"><a href="#cb1-5" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="cn">salmon</span><span class="op">;</span></span>
|
|||
|
<span id="cb1-6"><a href="#cb1-6" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p>With Sass, you could store this color in a Sass variable and use it
|
|||
|
in the styling rules to produce the same CSS, resulting in a single
|
|||
|
entry point for the color’s value. This simple Sass tool can make CSS
|
|||
|
styling a lot easier to reason about, making styles a lot easier to
|
|||
|
customize and maintain.</p>
|
|||
|
<div class="sourceCode" id="cb2"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb2-1"><a href="#cb2-1" tabindex="-1"></a>$main-color<span class="in">:</span> salmon;</span>
|
|||
|
<span id="cb2-2"><a href="#cb2-2" tabindex="-1"></a>a {</span>
|
|||
|
<span id="cb2-3"><a href="#cb2-3" tabindex="-1"></a> <span class="kw">color</span><span class="ch">:</span> $<span class="dv">main-color</span><span class="op">;</span></span>
|
|||
|
<span id="cb2-4"><a href="#cb2-4" tabindex="-1"></a>}</span>
|
|||
|
<span id="cb2-5"><a href="#cb2-5" tabindex="-1"></a>button {</span>
|
|||
|
<span id="cb2-6"><a href="#cb2-6" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> $<span class="dv">main-color</span><span class="op">;</span></span>
|
|||
|
<span id="cb2-7"><a href="#cb2-7" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p>Sass variables are not the only Sass tool useful for reducing
|
|||
|
complexity. For Sass and <strong>sass</strong> newcomers, this vignette
|
|||
|
first covers how to use basic Sass tools like <a href="#variables">variables</a>, <a href="#mixins">mixins</a>, and <a href="#functions">functions</a> in the <strong>sass</strong> R package.
|
|||
|
After the basics, you’ll also learn how to write <a href="#layering">composable <strong>sass</strong></a> that allows users
|
|||
|
to easily override your styling defaults and developers to <a href="#includes">include</a> your Sass in their styling projects. You’ll
|
|||
|
also learn how to control the CSS output (e.g., <a href="#compression">compress</a> and <a href="#caching">cache</a> it),
|
|||
|
and how to use it in <a href="#shiny"><strong>shiny</strong></a> &
|
|||
|
<a href="#rmarkdown"><strong>rmarkdown</strong></a>.</p>
|
|||
|
<p>By mastering these concepts, you’ll not only be able to leverage the
|
|||
|
advantages of using Sass over CSS, but you’ll also have the basis needed
|
|||
|
to develop R interfaces to Sass projects that allow users to easily
|
|||
|
customize your styling templates <em>without any knowledge of
|
|||
|
Sass/CSS</em>. For an example, see the <a href="https://github.com/rstudio/bslib"><strong>bslib</strong> R
|
|||
|
package</a>, which provides a interface to <a href="https://getbootstrap.com/docs/4.0/getting-started/theming/">Bootstrap
|
|||
|
Sass</a> through easy-to-use functions like
|
|||
|
<code>bs_theme_add_variables()</code>.</p>
|
|||
|
</div>
|
|||
|
<div id="basics" class="section level2">
|
|||
|
<h2>Sass Basics</h2>
|
|||
|
<div id="variables" class="section level3">
|
|||
|
<h3>Variables</h3>
|
|||
|
<p><a href="https://sass-lang.com/guide#topic-2">Sass variables</a> are
|
|||
|
a great mechanism for simplifying and exposing CSS logic to users. To
|
|||
|
create a variable, assign a value (likely a CSS <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/CSS_basics">property
|
|||
|
value</a>) to a name, then refer to it by name in downstream Sass code.
|
|||
|
In this minimal example, we create a <code>body-bg</code> variable then
|
|||
|
use it to generate a single <a href="https://sass-lang.com/documentation//style-rules">style rule</a>,
|
|||
|
but as we’ll see later, variables can also be used inside of other
|
|||
|
arbitrary Sass code (e.g., functions, mixins, etc).</p>
|
|||
|
<div class="sourceCode" id="cb3"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb3-1"><a href="#cb3-1" tabindex="-1"></a><span class="fu">library</span>(sass)</span>
|
|||
|
<span id="cb3-2"><a href="#cb3-2" tabindex="-1"></a>variable <span class="ot"><-</span> <span class="st">"$body-bg: red;"</span></span>
|
|||
|
<span id="cb3-3"><a href="#cb3-3" tabindex="-1"></a>rule <span class="ot"><-</span> <span class="st">"body { background-color: $body-bg; }"</span></span>
|
|||
|
<span id="cb3-4"><a href="#cb3-4" tabindex="-1"></a><span class="fu">sass</span>(<span class="at">input =</span> <span class="fu">list</span>(variable, rule))</span></code></pre></div>
|
|||
|
<div class="sourceCode" id="cb4"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb4-1"><a href="#cb4-1" tabindex="-1"></a><span class="co">/* CSS */</span></span>
|
|||
|
<span id="cb4-2"><a href="#cb4-2" tabindex="-1"></a>body { </span>
|
|||
|
<span id="cb4-3"><a href="#cb4-3" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="cn">red</span><span class="op">;</span></span>
|
|||
|
<span id="cb4-4"><a href="#cb4-4" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p>A more convenient and readable way to create Sass variables in R is
|
|||
|
to use a named <code>list()</code>. Also, it’s a good idea to add the
|
|||
|
<code>!default</code> flag after the value since it provides users of
|
|||
|
your Sass an opportunity to set their own value. We’ll learn more about
|
|||
|
defaults in <a href="#layering">layering</a>, but for now, just note
|
|||
|
that the <code>!default</code> flag says use this value only if that
|
|||
|
variable isn’t already defined:</p>
|
|||
|
<div class="sourceCode" id="cb5"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb5-1"><a href="#cb5-1" tabindex="-1"></a>user_default <span class="ot"><-</span> <span class="fu">list</span>(<span class="st">"body-bg"</span> <span class="ot">=</span> <span class="st">"blue !default"</span>)</span>
|
|||
|
<span id="cb5-2"><a href="#cb5-2" tabindex="-1"></a>default <span class="ot"><-</span> <span class="fu">list</span>(<span class="st">"body-bg"</span> <span class="ot">=</span> <span class="st">"red !default"</span>)</span>
|
|||
|
<span id="cb5-3"><a href="#cb5-3" tabindex="-1"></a><span class="fu">sass</span>(<span class="at">input =</span> <span class="fu">list</span>(user_default, default, rule))</span></code></pre></div>
|
|||
|
<div class="sourceCode" id="cb6"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb6-1"><a href="#cb6-1" tabindex="-1"></a><span class="co">/* CSS */</span></span>
|
|||
|
<span id="cb6-2"><a href="#cb6-2" tabindex="-1"></a>body { </span>
|
|||
|
<span id="cb6-3"><a href="#cb6-3" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="cn">blue</span><span class="op">;</span></span>
|
|||
|
<span id="cb6-4"><a href="#cb6-4" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
</div>
|
|||
|
<div id="functions" class="section level3">
|
|||
|
<h3>Functions</h3>
|
|||
|
<p>Sass comes with a variety of <a href="https://sass-lang.com/documentation//modules">built-in
|
|||
|
functions</a> (i.e., you don’t have to <a href="#imports">import</a>
|
|||
|
anything to start using them) which are useful for working with CSS
|
|||
|
values (<a href="https://sass-lang.com/documentation//modules/color">colors</a>, <a href="https://sass-lang.com/documentation//modules/math">numbers</a>, <a href="https://sass-lang.com/documentation//modules/string">strings</a>,
|
|||
|
etc). These built-in functions are primarily useful modifying or
|
|||
|
combining CSS values in such a way that isn’t possible with CSS. Here we
|
|||
|
use the <code>rgba()</code> to add alpha blending to <code>black</code>
|
|||
|
and assign the result to a variable.<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a></p>
|
|||
|
<div class="sourceCode" id="cb7"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb7-1"><a href="#cb7-1" tabindex="-1"></a>variable <span class="ot"><-</span> <span class="fu">list</span>(<span class="st">"body-bg"</span> <span class="ot">=</span> <span class="st">"rgba(black, 0.8)"</span>)</span>
|
|||
|
<span id="cb7-2"><a href="#cb7-2" tabindex="-1"></a><span class="fu">sass</span>(<span class="at">input =</span> <span class="fu">list</span>(variable, rule))</span></code></pre></div>
|
|||
|
<div class="sourceCode" id="cb8"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb8-1"><a href="#cb8-1" tabindex="-1"></a><span class="co">/* CSS */</span></span>
|
|||
|
<span id="cb8-2"><a href="#cb8-2" tabindex="-1"></a>body {</span>
|
|||
|
<span id="cb8-3"><a href="#cb8-3" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="fu">rgba(</span><span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0.8</span><span class="fu">)</span><span class="op">;</span></span>
|
|||
|
<span id="cb8-4"><a href="#cb8-4" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p>Sass also provides the ability to define your own functions through
|
|||
|
the <a href="https://sass-lang.com/documentation//at-rules/function"><code>@function</code>
|
|||
|
at-rule</a>. Like functions in most languages, there are four main
|
|||
|
components to a function definition: (1) the function <code>name</code>,
|
|||
|
(2) the function argument/inputs (e.g., <code>arg1</code>,
|
|||
|
<code>arg2</code>), (3) the function body which contains statements
|
|||
|
(i.e., <code>statement1</code>, <code>statement2</code>, etc.), and
|
|||
|
finally (4) a return <code>value</code>.</p>
|
|||
|
<div class="sourceCode" id="cb9"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb9-1"><a href="#cb9-1" tabindex="-1"></a><span class="sc">@</span>function <span class="fu">name</span>(arg1, arg2) {</span>
|
|||
|
<span id="cb9-2"><a href="#cb9-2" tabindex="-1"></a> statement1;</span>
|
|||
|
<span id="cb9-3"><a href="#cb9-3" tabindex="-1"></a> statement2;</span>
|
|||
|
<span id="cb9-4"><a href="#cb9-4" tabindex="-1"></a> <span class="sc">@</span>return value;</span>
|
|||
|
<span id="cb9-5"><a href="#cb9-5" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p><br></p>
|
|||
|
<p>For an example of where creating your function becomes useful,
|
|||
|
consider this <code>color-contrast()</code> function, inspired by <a href="https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color/3943023#3943023">this
|
|||
|
SO answer</a> to a common problem that arises when allowing users
|
|||
|
control over background color of something (e.g., the document body).
|
|||
|
We’d like to strive for styling rules that are smart enough to overlay
|
|||
|
white text on a dark colored background and black text on a light
|
|||
|
colored background. <code>color-contrast()</code> helps us achieve this
|
|||
|
since, given a dark color, it returns white; and given a light color, it
|
|||
|
returns black.</p>
|
|||
|
<div class="sourceCode" id="cb10"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb10-1"><a href="#cb10-1" tabindex="-1"></a><span class="sc">@</span>function color<span class="sc">-</span><span class="fu">contrast</span>(<span class="sc">$</span>color) {</span>
|
|||
|
<span id="cb10-2"><a href="#cb10-2" tabindex="-1"></a> <span class="sc">@</span>return <span class="cf">if</span>(</span>
|
|||
|
<span id="cb10-3"><a href="#cb10-3" tabindex="-1"></a> <span class="fu">red</span>(<span class="sc">$</span>color) <span class="sc">*</span> <span class="fl">0.299</span> <span class="sc">+</span> <span class="fu">green</span>(<span class="sc">$</span>color) <span class="sc">*</span> <span class="fl">0.587</span> <span class="sc">+</span> <span class="fu">blue</span>(<span class="sc">$</span>color) <span class="sc">*</span> <span class="fl">0.114</span> <span class="sc">></span> <span class="dv">186</span>,</span>
|
|||
|
<span id="cb10-4"><a href="#cb10-4" tabindex="-1"></a> black, white</span>
|
|||
|
<span id="cb10-5"><a href="#cb10-5" tabindex="-1"></a> );</span>
|
|||
|
<span id="cb10-6"><a href="#cb10-6" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p><br></p>
|
|||
|
<p>By saving this function to a file named
|
|||
|
<code>color-contrast.scss</code>, it can then be <a href="#imports">imported</a> and used in the following way. For a live
|
|||
|
example of this in action, consider <a href="https://gallery.shinyapps.io/sass-font/">this Shiny app</a> which
|
|||
|
allows the user to interactively choose a background color and the
|
|||
|
title’s font color automatically updates to an appropriate color
|
|||
|
contrast. <a href="#shiny-dynamic">See here</a> for more on allowing
|
|||
|
<strong>shiny</strong> users to influence styling on the page using
|
|||
|
<strong>sass</strong>.</p>
|
|||
|
<div class="sourceCode" id="cb11"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb11-1"><a href="#cb11-1" tabindex="-1"></a><span class="fu">sass</span>(</span>
|
|||
|
<span id="cb11-2"><a href="#cb11-2" tabindex="-1"></a> <span class="fu">list</span>(</span>
|
|||
|
<span id="cb11-3"><a href="#cb11-3" tabindex="-1"></a> variable,</span>
|
|||
|
<span id="cb11-4"><a href="#cb11-4" tabindex="-1"></a> <span class="fu">sass_file</span>(<span class="st">"color-contrast.scss"</span>),</span>
|
|||
|
<span id="cb11-5"><a href="#cb11-5" tabindex="-1"></a> <span class="st">"body {</span></span>
|
|||
|
<span id="cb11-6"><a href="#cb11-6" tabindex="-1"></a><span class="st"> background-color: $body-bg;</span></span>
|
|||
|
<span id="cb11-7"><a href="#cb11-7" tabindex="-1"></a><span class="st"> color: color-contrast($body-bg);</span></span>
|
|||
|
<span id="cb11-8"><a href="#cb11-8" tabindex="-1"></a><span class="st"> }"</span></span>
|
|||
|
<span id="cb11-9"><a href="#cb11-9" tabindex="-1"></a> )</span>
|
|||
|
<span id="cb11-10"><a href="#cb11-10" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
<div class="sourceCode" id="cb12"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb12-1"><a href="#cb12-1" tabindex="-1"></a><span class="co">/* CSS */</span></span>
|
|||
|
<span id="cb12-2"><a href="#cb12-2" tabindex="-1"></a>body {</span>
|
|||
|
<span id="cb12-3"><a href="#cb12-3" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="fu">rgba(</span><span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0.8</span><span class="fu">)</span><span class="op">;</span></span>
|
|||
|
<span id="cb12-4"><a href="#cb12-4" tabindex="-1"></a> <span class="kw">color</span><span class="ch">:</span> <span class="cn">white</span><span class="op">;</span></span>
|
|||
|
<span id="cb12-5"><a href="#cb12-5" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p><strong>NOTE</strong>: <code>bslib::bs_theme()</code> provides it’s
|
|||
|
own, more sophisticated, version of <code>color-contrast()</code> that
|
|||
|
you can use like so:
|
|||
|
<code>sass::sass_partial("body{color: color-contrast($body-bg)}", bs_theme())</code></p>
|
|||
|
</div>
|
|||
|
<div id="imports" class="section level3">
|
|||
|
<h3>Importing</h3>
|
|||
|
<p>In practice, you’ll want to write your Sass code in
|
|||
|
<code>.scss</code> (<a href="https://sass-lang.com/documentation//syntax">or
|
|||
|
<code>.sass</code></a>) files (instead of inside R strings). That way
|
|||
|
you can leverage things like syntax highlighting in RStudio (or your
|
|||
|
favorite IDE) and make it easier for others to import your Sass into
|
|||
|
their workflow. For example, if I have <code>.scss</code> file in my
|
|||
|
working directory, say <code>my-style.scss</code>, I can compile it this
|
|||
|
way:</p>
|
|||
|
<div class="sourceCode" id="cb13"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb13-1"><a href="#cb13-1" tabindex="-1"></a><span class="fu">sass</span>(<span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>))</span></code></pre></div>
|
|||
|
<p><img src="data:image/png;base64,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
|
|||
|
<div class="sourceCode" id="cb14"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb14-1"><a href="#cb14-1" tabindex="-1"></a><span class="co">/* CSS */</span></span>
|
|||
|
<span id="cb14-2"><a href="#cb14-2" tabindex="-1"></a>body {</span>
|
|||
|
<span id="cb14-3"><a href="#cb14-3" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="fu">rgba(</span><span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0.8</span><span class="fu">)</span><span class="op">;</span></span>
|
|||
|
<span id="cb14-4"><a href="#cb14-4" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p>This works because <code>sass_file()</code> uses
|
|||
|
<code>sass_import()</code> to generate an <code>@import</code> at-rule.
|
|||
|
If you visit the <a href="https://sass-lang.com/documentation//at-rules/import">docs for
|
|||
|
<code>@import</code></a>, you’ll notice there’s more you can do that
|
|||
|
import local <code>.scss</code>, like import local or remote
|
|||
|
<code>.css</code> files, import font files, and more. Note also that
|
|||
|
<code>{sass}</code> also provides tools that make importing of local
|
|||
|
font files easier – see <code>font_google()</code> to learn more.</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="file-import" class="section level2">
|
|||
|
<h2>Font imports</h2>
|
|||
|
<p>Importing font file(s) directly in Sass/CSS/HTML can be a headache to
|
|||
|
implement. This is especially true if you want to serve font files so
|
|||
|
that a custom font renders on any client machine, even if the client is
|
|||
|
without an internet connection. To make this easier, <code>{sass}</code>
|
|||
|
provides a <code>font_google()</code> which can be used to download,
|
|||
|
cache, import, and serve the relevant font files all at once.</p>
|
|||
|
<div class="sourceCode" id="cb15"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb15-1"><a href="#cb15-1" tabindex="-1"></a><span class="fu">library</span>(htmltools)</span>
|
|||
|
<span id="cb15-2"><a href="#cb15-2" tabindex="-1"></a></span>
|
|||
|
<span id="cb15-3"><a href="#cb15-3" tabindex="-1"></a>my_font <span class="ot"><-</span> <span class="fu">list</span>(<span class="st">"my-font"</span> <span class="ot">=</span> <span class="fu">font_google</span>(<span class="st">"Pacifico"</span>))</span>
|
|||
|
<span id="cb15-4"><a href="#cb15-4" tabindex="-1"></a>css <span class="ot"><-</span> <span class="fu">sass</span>(</span>
|
|||
|
<span id="cb15-5"><a href="#cb15-5" tabindex="-1"></a> <span class="fu">list</span>(</span>
|
|||
|
<span id="cb15-6"><a href="#cb15-6" tabindex="-1"></a> my_font,</span>
|
|||
|
<span id="cb15-7"><a href="#cb15-7" tabindex="-1"></a> <span class="fu">list</span>(<span class="st">"body {font-family: $my-font}"</span>)</span>
|
|||
|
<span id="cb15-8"><a href="#cb15-8" tabindex="-1"></a> )</span>
|
|||
|
<span id="cb15-9"><a href="#cb15-9" tabindex="-1"></a>)</span>
|
|||
|
<span id="cb15-10"><a href="#cb15-10" tabindex="-1"></a></span>
|
|||
|
<span id="cb15-11"><a href="#cb15-11" tabindex="-1"></a><span class="fu">shinyApp</span>(</span>
|
|||
|
<span id="cb15-12"><a href="#cb15-12" tabindex="-1"></a> <span class="fu">fluidPage</span>(</span>
|
|||
|
<span id="cb15-13"><a href="#cb15-13" tabindex="-1"></a> <span class="st">"Hello"</span>,</span>
|
|||
|
<span id="cb15-14"><a href="#cb15-14" tabindex="-1"></a> tags<span class="sc">$</span><span class="fu">style</span>(css)</span>
|
|||
|
<span id="cb15-15"><a href="#cb15-15" tabindex="-1"></a> ), </span>
|
|||
|
<span id="cb15-16"><a href="#cb15-16" tabindex="-1"></a> <span class="cf">function</span>(...) {}</span>
|
|||
|
<span id="cb15-17"><a href="#cb15-17" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
<p><img src="data:image/png;base64,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
|
|||
|
<p>To import non-Google fonts, use either <code>font_link()</code> or
|
|||
|
<code>font_face()</code>. The former is for importing fonts via a remote
|
|||
|
URL whereas the former could be use to import any font locally (or
|
|||
|
remotely).</p>
|
|||
|
<div id="mixins" class="section level3">
|
|||
|
<h3>Mixins</h3>
|
|||
|
<p>Similar to how functions are useful for encapsulating
|
|||
|
<em>computation</em> in a reusable unit, <a href="https://sass-lang.com/documentation//at-rules/mixin">mixins</a>
|
|||
|
are useful for doing the same with <em>styling rules</em> (i.e.,
|
|||
|
packaging them into a reusable unit). Technically speaking, mixins are
|
|||
|
similar to functions in that they require a <code>name</code>, may have
|
|||
|
arguments, as well as any number of statements. However, they differ in
|
|||
|
that they require the return value to be a <a href="https://sass-lang.com/documentation//style-rules">style rule</a>,
|
|||
|
and when called, need to be <code>@include</code>d in a larger style
|
|||
|
rule in order to generate any CSS.</p>
|
|||
|
<p>For some examples, please see the <a href="https://sass-lang.com/documentation//at-rules/mixin">Sass mixin
|
|||
|
documentation</a>.</p>
|
|||
|
</div>
|
|||
|
<div id="more-basics" class="section level3">
|
|||
|
<h3>More basics</h3>
|
|||
|
<p>This vignette intentionally doesn’t try to re-invent the existing and
|
|||
|
wonderful <a href="https://sass-lang.com/documentation/">Sass
|
|||
|
documentation</a>. There you’ll find many more useful things as you
|
|||
|
start to write more Sass, such as <a href="https://sass-lang.com/documentation//at-rules/control">control
|
|||
|
flow</a>, <a href="https://sass-lang.com/documentation//values/lists">lists</a>, <a href="https://sass-lang.com/documentation//values/maps">maps</a>, <a href="https://sass-lang.com/documentation//interpolation">interpolation</a>,
|
|||
|
and more.</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="layering" class="section level2">
|
|||
|
<h2>Composable sass</h2>
|
|||
|
<p>To make Sass code more composable with other Sass code (e.g.,
|
|||
|
allowing others to change your variable defaults or import a function or
|
|||
|
mixin you’ve defined), consider partitioning your Sass code into a
|
|||
|
<code>sass::sass_layer()</code>. The main idea is to split your Sass
|
|||
|
into 4 parts: <a href="#functions"><code>functions</code></a>,
|
|||
|
<code>defaults</code> (i.e. <a href="#variables">variable defaults</a>),
|
|||
|
<a href="#mixins"><code>mixins</code></a>, and <code>rules</code> (i.e.,
|
|||
|
styling rules).</p>
|
|||
|
<div class="sourceCode" id="cb16"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb16-1"><a href="#cb16-1" tabindex="-1"></a>layer1 <span class="ot"><-</span> <span class="fu">sass_layer</span>(</span>
|
|||
|
<span id="cb16-2"><a href="#cb16-2" tabindex="-1"></a> <span class="at">functions =</span> <span class="fu">sass_file</span>(<span class="st">"color-contrast.scss"</span>),</span>
|
|||
|
<span id="cb16-3"><a href="#cb16-3" tabindex="-1"></a> <span class="at">defaults =</span> <span class="fu">list</span>(<span class="st">"body-bg"</span> <span class="ot">=</span> <span class="st">"black !default"</span>),</span>
|
|||
|
<span id="cb16-4"><a href="#cb16-4" tabindex="-1"></a> <span class="at">rules =</span> <span class="st">"body{background-color: $body-bg; color: color-contrast($body-bg)}"</span></span>
|
|||
|
<span id="cb16-5"><a href="#cb16-5" tabindex="-1"></a>)</span>
|
|||
|
<span id="cb16-6"><a href="#cb16-6" tabindex="-1"></a><span class="fu">as_sass</span>(layer1)</span></code></pre></div>
|
|||
|
<div class="sourceCode" id="cb17"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb17-1"><a href="#cb17-1" tabindex="-1"></a><span class="co">/* CSS */</span></span>
|
|||
|
<span id="cb17-2"><a href="#cb17-2" tabindex="-1"></a>body {</span>
|
|||
|
<span id="cb17-3"><a href="#cb17-3" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="cn">black</span><span class="op">;</span></span>
|
|||
|
<span id="cb17-4"><a href="#cb17-4" tabindex="-1"></a> <span class="kw">color</span><span class="ch">:</span> <span class="cn">white</span><span class="op">;</span></span>
|
|||
|
<span id="cb17-5"><a href="#cb17-5" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<p>This allows downstream <code>sass_layer()</code>s to be
|
|||
|
<code>sass_bundle()</code>d into a single layer, where
|
|||
|
<code>defaults</code> in downstream layers are granted higher priority.
|
|||
|
More specifically, this means:</p>
|
|||
|
<ul>
|
|||
|
<li><code>defaults</code> for <code>layer2</code> are placed
|
|||
|
<em>before</em> <code>defaults</code> for <code>layer1</code>.
|
|||
|
<ul>
|
|||
|
<li>Allowing downstream Sass to override variable defaults in upstream
|
|||
|
Sass.</li>
|
|||
|
</ul></li>
|
|||
|
<li><code>rules</code> for <code>layer2</code> are placed <em>after</em>
|
|||
|
<code>rules</code> for <code>layer1</code>.
|
|||
|
<ul>
|
|||
|
<li>Allows downstream rules to take precedence over upstream rules (<a href="https://css-tricks.com/precedence-css-order-css-matters/">precedence</a>
|
|||
|
matters when there are multiple rules with the same level of <a href="https://css-tricks.com/specifics-on-css-specificity/">specificity</a>).</li>
|
|||
|
</ul></li>
|
|||
|
</ul>
|
|||
|
<div class="sourceCode" id="cb18"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb18-1"><a href="#cb18-1" tabindex="-1"></a>layer2 <span class="ot"><-</span> <span class="fu">sass_layer</span>(</span>
|
|||
|
<span id="cb18-2"><a href="#cb18-2" tabindex="-1"></a> <span class="at">defaults =</span> <span class="fu">list</span>(<span class="st">"body-bg"</span> <span class="ot">=</span> <span class="st">"white !default"</span>)</span>
|
|||
|
<span id="cb18-3"><a href="#cb18-3" tabindex="-1"></a>)</span>
|
|||
|
<span id="cb18-4"><a href="#cb18-4" tabindex="-1"></a><span class="fu">sass</span>(<span class="fu">sass_bundle</span>(layer1, layer2))</span></code></pre></div>
|
|||
|
<div class="sourceCode" id="cb19"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb19-1"><a href="#cb19-1" tabindex="-1"></a><span class="co">/* CSS */</span></span>
|
|||
|
<span id="cb19-2"><a href="#cb19-2" tabindex="-1"></a>body {</span>
|
|||
|
<span id="cb19-3"><a href="#cb19-3" tabindex="-1"></a> <span class="kw">background-color</span><span class="ch">:</span> <span class="cn">white</span><span class="op">;</span></span>
|
|||
|
<span id="cb19-4"><a href="#cb19-4" tabindex="-1"></a> <span class="kw">color</span><span class="ch">:</span> <span class="cn">black</span><span class="op">;</span></span>
|
|||
|
<span id="cb19-5"><a href="#cb19-5" tabindex="-1"></a>}</span></code></pre></div>
|
|||
|
<div id="imports-relative" class="section level3">
|
|||
|
<h3>Resolving relative imports</h3>
|
|||
|
<p>Another problem that <code>sass_layer()</code> helps solve is that
|
|||
|
sometimes your Sass code might want to <a href="#imports">import</a> a
|
|||
|
local file using a relative path that <em>you</em> know how to resolve,
|
|||
|
but not necessarily the person who eventually compiles your Sass. To
|
|||
|
solve this issue, provide a named character vector to
|
|||
|
<code>file_attachments</code>, pointing the relevant relative path(s) to
|
|||
|
the appropriate absolute path(s). Here’s a contrived example of how that
|
|||
|
might look (<a href="https://github.com/rstudio/bslib/blob/9c973e9/R/layers.R#L75-L77">here’s</a>
|
|||
|
a more real example of using it in an R package).</p>
|
|||
|
<div class="sourceCode" id="cb20"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb20-1"><a href="#cb20-1" tabindex="-1"></a><span class="fu">sass_layer</span>(</span>
|
|||
|
<span id="cb20-2"><a href="#cb20-2" tabindex="-1"></a> <span class="at">declarations =</span> <span class="st">"@import url('fonts/Source_Sans_Pro_300.ttf')"</span>,</span>
|
|||
|
<span id="cb20-3"><a href="#cb20-3" tabindex="-1"></a> <span class="at">file_attachments =</span> <span class="fu">c</span>(</span>
|
|||
|
<span id="cb20-4"><a href="#cb20-4" tabindex="-1"></a> <span class="at">fonts =</span> <span class="st">'/full/path/to/my/local/fonts'</span></span>
|
|||
|
<span id="cb20-5"><a href="#cb20-5" tabindex="-1"></a> )</span>
|
|||
|
<span id="cb20-6"><a href="#cb20-6" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
</div>
|
|||
|
<div id="html-dependencies" class="section level3">
|
|||
|
<h3>Attaching HTML dependencies</h3>
|
|||
|
<p>Another problem that <code>sass_layer()</code> helps solve is that
|
|||
|
sometimes you want to attach other HTML dependencies to your Sass/CSS
|
|||
|
(e.g., JavaScript, other CSS, etc). For this reason,
|
|||
|
<code>sass_layer()</code> has a <code>html_deps</code> argument to which
|
|||
|
you can provide <code>htmltools::htmlDependency()</code> objects.
|
|||
|
<code>sass()</code> preserves these, as well as any other HTML
|
|||
|
dependencies attached to it’s input, by including them in the return
|
|||
|
value. This ensures that, when you include <code>sass()</code> in <a href="#rmarkdown"><strong>rmarkdown</strong></a> or <a href="#shiny-string"><strong>shiny</strong></a> those dependencies come
|
|||
|
along for the ride.</p>
|
|||
|
<p><strong>DISCLAIMER</strong>: If you want to use this feature
|
|||
|
<em>and</em> include <a href="#shiny-file">CSS as a file in shiny</a>,
|
|||
|
you’ll need to call <code>htmltools::htmlDependencies()</code> on the
|
|||
|
return value of <code>sass()</code> to get the dependencies, then
|
|||
|
include them in your user interface definition.</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="options" class="section level2">
|
|||
|
<h2>CSS output options</h2>
|
|||
|
<p>The <code>sass()</code> function provides a few arguments for
|
|||
|
controlling the CSS output it generates, including <code>output</code>,
|
|||
|
<code>options</code>, and <code>cache_options</code>. The following
|
|||
|
covers some of the most important options available.</p>
|
|||
|
<div id="output-file" class="section level3">
|
|||
|
<h3>Output to a file</h3>
|
|||
|
<p>If the CSS generated from <code>sass()</code> can be useful in more
|
|||
|
than one place, consider writing it to a file (instead of returning it
|
|||
|
as a string). To write CSS to a file, give a suitable file path to
|
|||
|
<code>sass()</code>’s <code>output</code> argument.</p>
|
|||
|
<div class="sourceCode" id="cb21"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb21-1"><a href="#cb21-1" tabindex="-1"></a><span class="fu">sass</span>(</span>
|
|||
|
<span id="cb21-2"><a href="#cb21-2" tabindex="-1"></a> <span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>),</span>
|
|||
|
<span id="cb21-3"><a href="#cb21-3" tabindex="-1"></a> <span class="at">output =</span> <span class="st">"my-style.css"</span></span>
|
|||
|
<span id="cb21-4"><a href="#cb21-4" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
</div>
|
|||
|
<div id="compression" class="section level3">
|
|||
|
<h3>Compression</h3>
|
|||
|
<p>By default, <code>sass()</code> outputs <code>'expanded'</code> CSS
|
|||
|
meaning there are lots of white-space and line-breaks included to make
|
|||
|
it more readable by humans. Computers don’t need all those unnecessary
|
|||
|
characters, so to speed up your page load time when you go to include
|
|||
|
the CSS in <a href="#shiny"><strong>shiny</strong></a> or <a href="#rmarkdown"><strong>rmarkdown</strong></a>, consider removing them
|
|||
|
altogether with <code>output_style = "compressed"</code>:</p>
|
|||
|
<div class="sourceCode" id="cb22"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb22-1"><a href="#cb22-1" tabindex="-1"></a><span class="fu">sass</span>(</span>
|
|||
|
<span id="cb22-2"><a href="#cb22-2" tabindex="-1"></a> <span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>),</span>
|
|||
|
<span id="cb22-3"><a href="#cb22-3" tabindex="-1"></a> <span class="at">options =</span> <span class="fu">sass_options</span>(<span class="at">output_style =</span> <span class="st">"compressed"</span>)</span>
|
|||
|
<span id="cb22-4"><a href="#cb22-4" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
</div>
|
|||
|
<div id="source-maps" class="section level3">
|
|||
|
<h3>Source maps</h3>
|
|||
|
<p>When compressing the CSS output, it can be useful to include a <a href="https://web.dev/articles/source-maps">source map</a> so that it’s
|
|||
|
easier to inspect the CSS from the website. The easiest way to include a
|
|||
|
source map is to set <code>source_map_embed = TRUE</code>:</p>
|
|||
|
<div class="sourceCode" id="cb23"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb23-1"><a href="#cb23-1" tabindex="-1"></a><span class="fu">sass</span>(</span>
|
|||
|
<span id="cb23-2"><a href="#cb23-2" tabindex="-1"></a> <span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>),</span>
|
|||
|
<span id="cb23-3"><a href="#cb23-3" tabindex="-1"></a> <span class="at">options =</span> <span class="fu">sass_options</span>(</span>
|
|||
|
<span id="cb23-4"><a href="#cb23-4" tabindex="-1"></a> <span class="at">output_style =</span> <span class="st">"compressed"</span>,</span>
|
|||
|
<span id="cb23-5"><a href="#cb23-5" tabindex="-1"></a> <span class="at">source_map_embed =</span> <span class="cn">TRUE</span></span>
|
|||
|
<span id="cb23-6"><a href="#cb23-6" tabindex="-1"></a> )</span>
|
|||
|
<span id="cb23-7"><a href="#cb23-7" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
</div>
|
|||
|
<div id="caching" class="section level3">
|
|||
|
<h3>Caching</h3>
|
|||
|
<p>Sometimes calling <code>sass()</code> can be computationally
|
|||
|
expensive, in which case, it can be useful to leverage its caching
|
|||
|
capability. Caching is enabled by default, unless Shiny’s Developer Mode
|
|||
|
(<code>shiny::devmode()</code>) is enabled. To explicitly enable
|
|||
|
(disable), set <code>options(sass.cache = )</code> to <code>TRUE</code>
|
|||
|
(or <code>FALSE</code>):</p>
|
|||
|
<div class="sourceCode" id="cb24"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb24-1"><a href="#cb24-1" tabindex="-1"></a>withr<span class="sc">::</span><span class="fu">with_options</span>(</span>
|
|||
|
<span id="cb24-2"><a href="#cb24-2" tabindex="-1"></a> <span class="fu">list</span>(<span class="at">sass.cache =</span> <span class="cn">TRUE</span>),</span>
|
|||
|
<span id="cb24-3"><a href="#cb24-3" tabindex="-1"></a> <span class="fu">sass</span>(<span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>))</span>
|
|||
|
<span id="cb24-4"><a href="#cb24-4" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
<p>You can also configure the location, size, and age of file caching
|
|||
|
via <code>sass_file_cache()</code>, which can be passed directly to a
|
|||
|
<code>sass()</code> call:</p>
|
|||
|
<div class="sourceCode" id="cb25"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb25-1"><a href="#cb25-1" tabindex="-1"></a><span class="fu">sass</span>(</span>
|
|||
|
<span id="cb25-2"><a href="#cb25-2" tabindex="-1"></a> <span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>),</span>
|
|||
|
<span id="cb25-3"><a href="#cb25-3" tabindex="-1"></a> <span class="at">cache =</span> <span class="fu">sass_file_cache</span>(<span class="fu">getwd</span>(), <span class="at">max_size =</span> <span class="dv">100</span> <span class="sc">*</span> <span class="dv">1024</span><span class="sc">^</span><span class="dv">2</span>)</span>
|
|||
|
<span id="cb25-4"><a href="#cb25-4" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
<p>Or used with <code>sass_cache_set_dir()</code> to configure the file
|
|||
|
cache globally:</p>
|
|||
|
<div class="sourceCode" id="cb26"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb26-1"><a href="#cb26-1" tabindex="-1"></a><span class="fu">sass_cache_set_dir</span>(<span class="fu">getwd</span>(), <span class="fu">sass_file_cache</span>(<span class="fu">getwd</span>(), <span class="at">max_size =</span> <span class="dv">100</span> <span class="sc">*</span> <span class="dv">1024</span><span class="sc">^</span><span class="dv">2</span>))</span></code></pre></div>
|
|||
|
<p>Note that the location of the file cache defaults to
|
|||
|
<code>sass_cache_context_dir()</code>, which depends on the context in
|
|||
|
which it’s running. When inside a Shiny app, the cache location is
|
|||
|
relative to the app’s directory so the cache can persist and be shared
|
|||
|
across R processes. Otherwise, the context directory is a OS and package
|
|||
|
specific caching directory.</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="shiny" class="section level2">
|
|||
|
<h2>In shiny</h2>
|
|||
|
<p>There are two basic approaches to including the CSS that
|
|||
|
<code>sass()</code> returns as HTML in your <strong>shiny</strong> app.
|
|||
|
If you’re curious, the official <a href="https://shiny.rstudio.com/articles/css.html">shiny article on
|
|||
|
CSS</a> has more details with a couple different approaches. Regardless
|
|||
|
of the approach, consider leveraging <a href="#compression">compressing</a> and <a href="#caching">caching</a>
|
|||
|
the CSS output to make your app faster to load.</p>
|
|||
|
<div id="shiny-string" class="section level3">
|
|||
|
<h3>As a string</h3>
|
|||
|
<p>The character string that <code>sass()</code> returns is already
|
|||
|
marked as <code>HTML()</code><a href="#fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a>, so to include it in your
|
|||
|
<strong>shiny</strong> app, wrap it in a <code><style></code> tag.
|
|||
|
It’s not necessary to place this tag in the <code><head></code> of
|
|||
|
the document, but it’s good practice:</p>
|
|||
|
<div class="sourceCode" id="cb27"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb27-1"><a href="#cb27-1" tabindex="-1"></a><span class="fu">library</span>(shiny)</span>
|
|||
|
<span id="cb27-2"><a href="#cb27-2" tabindex="-1"></a>css <span class="ot"><-</span> <span class="fu">sass</span>(<span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>))</span>
|
|||
|
<span id="cb27-3"><a href="#cb27-3" tabindex="-1"></a><span class="fu">fluidPage</span>(</span>
|
|||
|
<span id="cb27-4"><a href="#cb27-4" tabindex="-1"></a> tags<span class="sc">$</span><span class="fu">head</span>(tags<span class="sc">$</span><span class="fu">style</span>(css),</span>
|
|||
|
<span id="cb27-5"><a href="#cb27-5" tabindex="-1"></a> ...</span>
|
|||
|
<span id="cb27-6"><a href="#cb27-6" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
</div>
|
|||
|
<div id="shiny-file" class="section level3">
|
|||
|
<h3>As a file</h3>
|
|||
|
<p>To write CSS to a file, give a suitable file path to
|
|||
|
<code>sass()</code>’s <code>output</code> argument. Here we write to a
|
|||
|
specially named <code>www/</code> subdirectory so that
|
|||
|
<strong>shiny</strong> will automatically make those file(s) available
|
|||
|
to the web app.</p>
|
|||
|
<div class="sourceCode" id="cb28"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb28-1"><a href="#cb28-1" tabindex="-1"></a><span class="fu">library</span>(shiny)</span>
|
|||
|
<span id="cb28-2"><a href="#cb28-2" tabindex="-1"></a><span class="fu">sass</span>(</span>
|
|||
|
<span id="cb28-3"><a href="#cb28-3" tabindex="-1"></a> <span class="fu">sass_file</span>(<span class="st">"my-style.scss"</span>),</span>
|
|||
|
<span id="cb28-4"><a href="#cb28-4" tabindex="-1"></a> <span class="at">output =</span> <span class="st">"www/my-style.css"</span></span>
|
|||
|
<span id="cb28-5"><a href="#cb28-5" tabindex="-1"></a>)</span>
|
|||
|
<span id="cb28-6"><a href="#cb28-6" tabindex="-1"></a><span class="fu">fluidPage</span>(</span>
|
|||
|
<span id="cb28-7"><a href="#cb28-7" tabindex="-1"></a> tags<span class="sc">$</span><span class="fu">head</span>(</span>
|
|||
|
<span id="cb28-8"><a href="#cb28-8" tabindex="-1"></a> tags<span class="sc">$</span><span class="fu">link</span>(<span class="at">href =</span> <span class="st">"my-style.css"</span>, <span class="at">rel =</span> <span class="st">"stylesheet"</span>, <span class="at">type =</span> <span class="st">"text/css"</span>)</span>
|
|||
|
<span id="cb28-9"><a href="#cb28-9" tabindex="-1"></a> ),</span>
|
|||
|
<span id="cb28-10"><a href="#cb28-10" tabindex="-1"></a> ...</span>
|
|||
|
<span id="cb28-11"><a href="#cb28-11" tabindex="-1"></a>)</span></code></pre></div>
|
|||
|
</div>
|
|||
|
<div id="shiny-dynamic" class="section level3">
|
|||
|
<h3>As a dynamic input</h3>
|
|||
|
<p>Sometimes it’s useful to allow users of your <strong>shiny</strong>
|
|||
|
app to be able to influence your app’s styling via
|
|||
|
<strong>shiny</strong> input(s). One way this can be done is via <a href="https://shiny.rstudio.com/articles/dynamic-ui.html">dynamic
|
|||
|
UI</a>, where you use <code>renderUI()</code>/<code>uiOutput()</code> to
|
|||
|
dynamically insert <a href="#shiny-string">CSS as an HTML string</a>
|
|||
|
whenever a relevant input changes. Be aware, however, that whenever you
|
|||
|
allow dynamic user input to generate <code>HTML()</code>, you’re leaving
|
|||
|
yourself open to security vulnerabilites; so try to avoid it, and
|
|||
|
<em>never</em> allow clients to enter free form <code>textInput()</code>
|
|||
|
without any sort of sanitation of the user input.</p>
|
|||
|
<p>Consider this basic example of using a <code>colourInput()</code>
|
|||
|
widget (from the <strong>colourpicker</strong> package) to choose the
|
|||
|
body’s background color, which triggers a call to
|
|||
|
<code>sass()</code>:</p>
|
|||
|
<div class="sourceCode" id="cb29"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb29-1"><a href="#cb29-1" tabindex="-1"></a><span class="fu">library</span>(shiny)</span>
|
|||
|
<span id="cb29-2"><a href="#cb29-2" tabindex="-1"></a></span>
|
|||
|
<span id="cb29-3"><a href="#cb29-3" tabindex="-1"></a>ui <span class="ot"><-</span> <span class="fu">fluidPage</span>(</span>
|
|||
|
<span id="cb29-4"><a href="#cb29-4" tabindex="-1"></a> <span class="fu">headerPanel</span>(<span class="st">"Sass Color Example"</span>),</span>
|
|||
|
<span id="cb29-5"><a href="#cb29-5" tabindex="-1"></a> colourpicker<span class="sc">::</span><span class="fu">colourInput</span>(<span class="st">"color"</span>, <span class="st">"Background Color"</span>, <span class="at">value =</span> <span class="st">"#6498d2"</span>, <span class="at">showColour =</span> <span class="st">"text"</span>),</span>
|
|||
|
<span id="cb29-6"><a href="#cb29-6" tabindex="-1"></a> <span class="fu">uiOutput</span>(<span class="st">"sass"</span>)</span>
|
|||
|
<span id="cb29-7"><a href="#cb29-7" tabindex="-1"></a>)</span>
|
|||
|
<span id="cb29-8"><a href="#cb29-8" tabindex="-1"></a></span>
|
|||
|
<span id="cb29-9"><a href="#cb29-9" tabindex="-1"></a>server <span class="ot"><-</span> <span class="cf">function</span>(input, output) {</span>
|
|||
|
<span id="cb29-10"><a href="#cb29-10" tabindex="-1"></a> output<span class="sc">$</span>sass <span class="ot"><-</span> <span class="fu">renderUI</span>({</span>
|
|||
|
<span id="cb29-11"><a href="#cb29-11" tabindex="-1"></a> tags<span class="sc">$</span><span class="fu">head</span>(tags<span class="sc">$</span><span class="fu">style</span>(<span class="fu">css</span>()))</span>
|
|||
|
<span id="cb29-12"><a href="#cb29-12" tabindex="-1"></a> })</span>
|
|||
|
<span id="cb29-13"><a href="#cb29-13" tabindex="-1"></a> css <span class="ot"><-</span> <span class="fu">reactive</span>({</span>
|
|||
|
<span id="cb29-14"><a href="#cb29-14" tabindex="-1"></a> sass<span class="sc">::</span><span class="fu">sass</span>(<span class="fu">list</span>(</span>
|
|||
|
<span id="cb29-15"><a href="#cb29-15" tabindex="-1"></a> <span class="fu">list</span>(<span class="at">color =</span> input<span class="sc">$</span>color),</span>
|
|||
|
<span id="cb29-16"><a href="#cb29-16" tabindex="-1"></a> <span class="st">"body { background-color: $color; }"</span></span>
|
|||
|
<span id="cb29-17"><a href="#cb29-17" tabindex="-1"></a> ))</span>
|
|||
|
<span id="cb29-18"><a href="#cb29-18" tabindex="-1"></a> })</span>
|
|||
|
<span id="cb29-19"><a href="#cb29-19" tabindex="-1"></a>}</span>
|
|||
|
<span id="cb29-20"><a href="#cb29-20" tabindex="-1"></a></span>
|
|||
|
<span id="cb29-21"><a href="#cb29-21" tabindex="-1"></a><span class="fu">shinyApp</span>(ui, server)</span></code></pre></div>
|
|||
|
<p><br></p>
|
|||
|
<p><img src="data:image/gif;base64,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
|
|||
|
<p>Below are a few more sophisticated examples of dynamic input:</p>
|
|||
|
<ul>
|
|||
|
<li>Font Color
|
|||
|
<ul>
|
|||
|
<li><a href="https://gallery.shinyapps.io/sass-font" class="uri">https://gallery.shinyapps.io/sass-font</a></li>
|
|||
|
<li><code>shiny::runApp(system.file("sass-font", package = "sass"))</code></li>
|
|||
|
</ul></li>
|
|||
|
<li>Sizing
|
|||
|
<ul>
|
|||
|
<li><a href="https://gallery.shinyapps.io/sass-size" class="uri">https://gallery.shinyapps.io/sass-size</a></li>
|
|||
|
<li><code>shiny::runApp(system.file("sass-size", package = "sass"))</code></li>
|
|||
|
</ul></li>
|
|||
|
<li>Themes
|
|||
|
<ul>
|
|||
|
<li><a href="https://gallery.shinyapps.io/sass-theme" class="uri">https://gallery.shinyapps.io/sass-theme</a></li>
|
|||
|
<li><code>shiny::runApp(system.file("sass-theme", package = "sass"))</code></li>
|
|||
|
</ul></li>
|
|||
|
</ul>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="rmarkdown" class="section level2">
|
|||
|
<h2>In rmarkdown</h2>
|
|||
|
<p><strong>knitr</strong> <a href="https://github.com/yihui/knitr/pull/1666">recently gained</a> a
|
|||
|
Sass engine powered by the <strong>sass</strong> package. This means you
|
|||
|
can write Sass code directly into a code <code>sass</code> chunk and the
|
|||
|
resulting CSS will be included in the resulting document (The
|
|||
|
<code>echo = FALSE</code> prevents the Sass code from being shown in the
|
|||
|
resulting document).</p>
|
|||
|
<pre><code>```{sass, echo = FALSE}
|
|||
|
$body-bg: red;
|
|||
|
body{
|
|||
|
background-color: $body-bg;
|
|||
|
}
|
|||
|
```</code></pre>
|
|||
|
<p>If you like to write R <strong>sass</strong> code instead, you can do
|
|||
|
that as well, and by default it works similarly to the <code>sass</code>
|
|||
|
engine (except that the sass-specific code chunk options will be
|
|||
|
ignored, but you can specify those <a href="#options">options</a> via
|
|||
|
<code>sass::sass()</code> instead).</p>
|
|||
|
<pre><code>```{r, echo = FALSE}
|
|||
|
sass(sass_file("my-style.scss"))
|
|||
|
```</code></pre>
|
|||
|
<p>If syntax highlighting is enabled in your output document , it’s also
|
|||
|
possible to display the generated CSS (instead of embedding it as HTML)
|
|||
|
with syntax highlighting by setting the code chunk options
|
|||
|
<code>class.output='css'</code> and <code>comment=''</code>.
|
|||
|
Unfortunately, for some output formats, like
|
|||
|
<code>rmarkdown::html_vignette()</code>, syntax hightlighting isn’t
|
|||
|
supported, but for output formats like
|
|||
|
<code>rmarkdown::html_document()</code>, you can enable syntax
|
|||
|
highlighting by setting the <code>highlight</code> parameter to a
|
|||
|
non-default value (e.g., <code>tango</code>).</p>
|
|||
|
<pre><code>```{r, class.output='css', comment=''}
|
|||
|
sass(sass_file("my-style.scss"))
|
|||
|
```</code></pre>
|
|||
|
</div>
|
|||
|
<div class="footnotes footnotes-end-of-document">
|
|||
|
<hr />
|
|||
|
<ol>
|
|||
|
<li id="fn1"><p>Oh, by the way, the value of a variable may be an
|
|||
|
expression.<a href="#fnref1" class="footnote-back">↩︎</a></p></li>
|
|||
|
<li id="fn2"><p>Including <a href="#shiny-dynamic">dynamic user
|
|||
|
input</a> directly as <code>HTML()</code>, especially with free form
|
|||
|
inputs like <code>textInput()</code>, is a security vulnerability. Avoid
|
|||
|
it if you can.<a href="#fnref2" class="footnote-back">↩︎</a></p></li>
|
|||
|
</ol>
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<!-- code folding -->
|
|||
|
|
|||
|
|
|||
|
<!-- dynamically load mathjax for compatibility with self-contained -->
|
|||
|
<script>
|
|||
|
(function () {
|
|||
|
var script = document.createElement("script");
|
|||
|
script.type = "text/javascript";
|
|||
|
script.src = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
|
|||
|
document.getElementsByTagName("head")[0].appendChild(script);
|
|||
|
})();
|
|||
|
</script>
|
|||
|
|
|||
|
</body>
|
|||
|
</html>
|