Twitter uses image sprite and JavaScript to produce Like button animation. We would be giving same effect to checkbox by using Lightning component. Combination of Checkbox, Label and Box property of CSS3 is used to give final result.
Lightning Component will contain only declaration of checkbox as shown below.
TwitterLove.cmp
<aura:component > <input id="toggle-heart" type="checkbox" /> <label for="toggle-heart">❤</label> </aura:component>
Note : In above source code, heart UTF icon is getting replaced by emoji code, so refer this screen to see exact code written for Lightning Component.
We have used Sassy CSS (SCSS) in this demo, as it would be little bit hard to write pure CSS with animation. Once SCSS is written, we can use this online tool to convert it to CSS. All these are explained and build live on my channel.
TwitterLove.scss
$bubble-d: 4.5rem; // bubble diameter $bubble-r: .5*$bubble-d; // bubble-radius $particle-d: .375rem; $particle-r: .5*$particle-d; $shadow-list: (); // init shadow list $n-groups: 7.0; // number of groups $group-base-angle: 360deg/$n-groups; $group-distr-r: 1.0 * $bubble-r; // circular distribution radius for groups @for $i from 0 to $n-groups { // current group angle, starting fron 12 o'clock $group-curr-angle: $i * $group-base-angle - 90deg; // coords of the central point of current group of particles $xg: $group-distr-r * cos($group-curr-angle); $yg: $group-distr-r * sin($group-curr-angle); // add to shadow list $shadow-list: $shadow-list, $xg $yg; } @mixin bubble($ext) { transform: scale(1); border-color: #cc8ef5; border-width: $ext; } body { display: flex; justify-content: center; margin: 0; height: 100vh; } [id='toggle-heart'] { position: absolute; left: -100vw; &:checked + label { color: #e2264d; will-change: font-size; animation: heart 1s cubic-bezier(.17, .89, .32, 1.49); &:before, &:after { animation: inherit; animation-timing-function: cubic-bezier(.21, .61, .35, 1); } &:before { will-change: transform, border-width, border-color; animation-name: bubble; } } } [for='toggle-heart'] { align-self: center; position: relative; color: #aab8c2; font-size: 2em; cursor: pointer; &:before, &:after { position: absolute; z-index: -1; top: 50%; left: 50%; border-radius: 50%; content: ''; } &:before { box-sizing: border-box; margin: -$bubble-r; border: solid $bubble-r #e2264d; width: $bubble-d; height: $bubble-d; transform: scale(0); } &:after { margin: -$particle-r; width: $particle-d; height: $particle-d; box-shadow: $shadow-list; } } @keyframes heart { 0%, 17.5% { font-size: 0; } } @keyframes bubble { 15% { @include bubble($bubble-r); } 30%, 100% { @include bubble(0); } }
TwitterLove.css (CSS auto generated from SCSS)
.THIS { display: flex; justify-content: center; margin: 0; } .THIS[id='toggle-heart'] { position: absolute; left: -100vw; } .THIS[for='toggle-heart'] { color: #aab8c2; } .THIS[id='toggle-heart']:checked + label { color: #e2264d; } .THIS[for='toggle-heart'] { font-size: 2em; cursor: pointer; } .THIS[for='toggle-heart'] { align-self: center; margin-top: 100px; } @keyframes heart { 0%, 20% { font-size: 0; } } .THIS[id='toggle-heart']:checked + label { will-change: font-size; animation: heart 1s cubic-bezier(0.17, 0.89, 0.32, 1.49); } .THIS[for='toggle-heart'] { position: relative; } .THIS[for='toggle-heart']:before, .THIS[for='toggle-heart']:after { position: absolute; z-index: -1; top: 50%; left: 50%; border-radius: 50%; content: ''; } .THIS[for='toggle-heart']::before { margin: -2.25rem; width: 4.5rem; height: 4.5rem; } .THIS[for='toggle-heart']:before { box-sizing: border-box; border: solid 2.25rem #e2264d; transform: scale(0); } @keyframes bubble { 15% { border-color: #cc8ef5; border-width: 2.25rem; transform: scale(1); } 30%, 100% { border-color: #cc8ef5; border-width: 0; transform: scale(1); } } .THIS[id='toggle-heart']:checked + label::before, .THIS[id='toggle-heart']:checked + label::after { animation: inherit; animation-timing-function: cubic-bezier(0.21, 0.61, 0.35, 1); } .THIS[id='toggle-heart']:checked + label::before { will-change: transform, border-color, border-width; animation-name: bubble; } .THIS[id='toggle-heart']:checked + label:after { will-change: opacity, box-shadow; animation-name: particles; } .THIS[for='toggle-heart']:after { margin: -0.1875rem; width: 0.375rem; height: 0.375rem; } @keyframes particles { 0%, 20% { opacity: 0; } 25% { opacity: 1; box-shadow: 0.32476rem -2.4375rem 0 0rem #ff8080, -0.32476rem -2.0625rem 0 0rem #ffed80, 2.1082rem -1.26585rem 0 0rem #ffed80, 1.41004rem -1.53985rem 0 0rem #a4ff80, 2.30412rem 0.85901rem 0 0rem #a4ff80, 2.08305rem 0.14233rem 0 0rem #80ffc8, 0.76499rem 2.33702rem 0 0rem #80ffc8, 1.18748rem 1.71734rem 0 0rem #80c8ff, -1.35019rem 2.0552rem 0 0rem #80c8ff, -0.60229rem 1.99916rem 0 0rem #a480ff, -2.44865rem 0.22578rem 0 0rem #a480ff, -1.93852rem 0.77557rem 0 0rem #ff80ed, -1.70323rem -1.77366rem 0 0rem #ff80ed, -1.81501rem -1.03204rem 0 0rem #ff8080; } } .THIS[for='toggle-heart']:after { box-shadow: 0.32476rem -3rem 0 -0.1875rem #ff8080, -0.32476rem -2.625rem 0 -0.1875rem #ffed80, 2.54798rem -1.61656rem 0 -0.1875rem #ffed80, 1.84982rem -1.89057rem 0 -0.1875rem #a4ff80, 2.85252rem 0.98418rem 0 -0.1875rem #a4ff80, 2.63145rem 0.2675rem 0 -0.1875rem #80ffc8, 1.00905rem 2.84381rem 0 -0.1875rem #80ffc8, 1.43154rem 2.22414rem 0 -0.1875rem #80c8ff, -1.59425rem 2.562rem 0 -0.1875rem #80c8ff, -0.84635rem 2.50595rem 0 -0.1875rem #a480ff, -2.99705rem 0.35095rem 0 -0.1875rem #a480ff, -2.48692rem 0.90073rem 0 -0.1875rem #ff80ed, -2.14301rem -2.12438rem 0 -0.1875rem #ff80ed, -2.25479rem -1.38275rem 0 -0.1875rem #ff8080; } .THIS[id='toggle-heart']:checked + label:after { margin: -0.1875rem; width: 0.375rem; height: 0.375rem; /* box-shadow: $shadow-list;*/ box-shadow: 0.32476rem -3rem 0 -0.1875rem #ff8080, -0.32476rem -2.625rem 0 -0.1875rem #ffed80, 2.54798rem -1.61656rem 0 -0.1875rem #ffed80, 1.84982rem -1.89057rem 0 -0.1875rem #a4ff80, 2.85252rem 0.98418rem 0 -0.1875rem #a4ff80, 2.63145rem 0.2675rem 0 -0.1875rem #80ffc8, 1.00905rem 2.84381rem 0 -0.1875rem #80ffc8, 1.43154rem 2.22414rem 0 -0.1875rem #80c8ff, -1.59425rem 2.562rem 0 -0.1875rem #80c8ff, -0.84635rem 2.50595rem 0 -0.1875rem #a480ff, -2.99705rem 0.35095rem 0 -0.1875rem #a480ff, -2.48692rem 0.90073rem 0 -0.1875rem #ff80ed, -2.14301rem -2.12438rem 0 -0.1875rem #ff80ed, -2.25479rem -1.38275rem 0 -0.1875rem #ff8080; }
Next Step – Handling event in Lightning Component
We can register event on this component, so that whenever checkbox is checked, other components in Lightning components can be notified. This trailhead module would guide in much detail about handling events in Lightning Component.
Resources
- Live coding stream (My Channel)
- Recreating the Twitter Heart Animation (with One Element, No Images, and No JavaScript)
- sassmeister online SCSS playground
Leave a Reply