library(minicss)
library(htmltools)

Introduction

Animation using css consists of

  1. A set of keyframes describing the appearance at multiple timepoints
  2. An animation declaration (linked to a particular selector)

Simple animation in CSS

The following CSS code defines 2 keyframes - the first keyframe defines the colour as red, and the second keyframe defines the colour as green. This set of keyframes is given the name ‘example’.

The .ugly class contains the animation declaration which says the animation should take 1second and should alternate back-and-forth between the two given states forever (i.e. infinite loops)

@keyframes example1 {
    from { color: #ff0000; }
    to   { color: #00ff00; }
}

.ugly { animation: example1 1s infinite alternate; }

Create the individual frames with minicss

Create a keyframe by initialising an R6 object of class Keyframe

#>     from { color: #000; }

Create a keyframe by using the css_keyframe() function.

css_keyframe(time = 'to', colour = '#00f')
#>     to { color: #00f; }

Create a keyframe linked to a particular instant in time i.e. 10% through the animation cycle.

css_keyframe(time = "10%", color = '#123456')
#>     10% { color: #123456; }

Modify a keyframe

A Keyframe object behaves in the same way as Style object, individual declarations can be updated.

kf <- css_keyframe(time = 'to', colour = '#00f')
kf$update(margin = '10px')

kf
#>     to {
#>         color: #00f;
#>         margin: 10px;
#>     }

Combine individual keyframes into a Keyframes object

Method 1

#> @keyframes example {
#>     from { color: #123456; }
#>     to { color: #0000ff; }
#> }

Method 2

keyframes <- Keyframes$new(
  name = 'example',
  css_keyframe(time = "from", color = '#123456'),
  css_keyframe(time = "to"  , color = '#0000ff')
)

keyframes
#> @keyframes example {
#>     from { color: #123456; }
#>     to { color: #0000ff; }
#> }

Create an animation declaration

This will make use of auto-complete

#> animation: example 2s 3;

Putting it all together

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Construct individual frames
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
k1 <- css_keyframe('from', color = '#ffffff')
k2 <- css_keyframe('to'  , color = '#123456')
k2$update(css_prop$transform$translateX(40, 'px'))

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Combine frames into @keyframes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
kf <- css_keyframes('ex1', k1, k2)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create style to attach @keyframes to the 'h1' type
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
my_style <- css_style(".swish", font_size = "50px")
my_style$update(
    css_prop$animation('ex1', duration = 1, direction = 'alternate')
)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create a style sheet which includes 
#  - the style for the swish element (including an animation declaration)
#  - the keyframes definition
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
stylesheet <- css_stylesheet(my_style, kf)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create a small HTML snippet which uses this style sheet
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
html <- glue::glue("<html><head>
  <style>{stylesheet}</style>
  </head>
  <body>
  <p class='swish'> Hello #RStats </p>
  </body></html>")
#> <html><head>
#> <style>.swish {
#>     font-size: 50px;
#>     animation: ex1 1s infinite alternate;
#> }
#> @keyframes ex1 {
#>     from { color: #ffffff; }
#>     to {
#>         color: #123456;
#>         transform: translateX(40px);
#>     }
#> }</style>
#> </head>
#> <body>
#> <p class='swish'> Hello #RStats </p>
#> </body></html>

Hello #RStats