Audio fullscreen, Tooltip tweaks, Docs

This commit is contained in:
Sam Potts 2015-10-25 11:57:52 +11:00
parent 58f8cdd8c8
commit 125a95e9e1
8 changed files with 277 additions and 95 deletions

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

2
docs/dist/docs.css vendored

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,14 @@
// Examples // Examples
// ========================================================================== // ==========================================================================
video,
.plyr-video-embed {
border-radius: @border-radius-base;
}
.plyr-video-embed {
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
}
// Example players // Example players
.plyr { .plyr {
margin: 0 auto @padding-base; margin: 0 auto @padding-base;
@ -10,35 +18,11 @@
&-controls { &-controls {
border-radius: 0 0 @border-radius-base @border-radius-base; border-radius: 0 0 @border-radius-base @border-radius-base;
} }
}
.plyr-audio {
max-width: @example-width-audio;
.plyr-controls {
border-radius: @border-radius-base;
}
.plyr-progress {
border-radius: @border-radius-base @border-radius-base 0 0;
overflow: hidden;
}
}
video,
.plyr-video-embed {
border-radius: @border-radius-base;
}
.plyr-video-embed {
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
}
// Style full supported player
.plyr-video,
.plyr-youtube,
.plyr-vimeo {
video, video,
.plyr-video-embed { .plyr-video-embed {
border-radius: @border-radius-base @border-radius-base 0 0; border-radius: @border-radius-base @border-radius-base 0 0;
} }
&.plyr-fullscreen, &-fullscreen,
&.fullscreen-active { &.fullscreen-active {
max-width: none; max-width: none;
@ -52,7 +36,19 @@ video,
} }
} }
} }
.plyr-audio {
max-width: @example-width-audio;
.plyr-controls {
border-radius: @border-radius-base;
}
.plyr-progress {
border-radius: @border-radius-base @border-radius-base 0 0;
overflow: hidden;
}
}
// Style full supported player
.cite { .cite {
display: none; display: none;

155
readme.md
View File

@ -262,7 +262,7 @@ Options must be passed as an object to the `setup()` method as above.
<td><code>selectors</code></td> <td><code>selectors</code></td>
<td>Object</td> <td>Object</td>
<td>&mdash;</td> <td>&mdash;</td>
<td>See <code>plyr.js</code> in <code>/src</code> for more info. The only option you might want to change is <code>container</code> which is the hook used for `setup()`, the default is <code>.plyr</code>.</td> <td>See <code>plyr.js</code> in <code>/src</code> for more info. You probably don't need to change any of these.</td>
</tr> </tr>
<tr> <tr>
<td><code>classes</code></td> <td><code>classes</code></td>
@ -280,7 +280,7 @@ Options must be passed as an object to the `setup()` method as above.
<td><code>fullscreen</code></td> <td><code>fullscreen</code></td>
<td>Object</td> <td>Object</td>
<td>&mdash;</td> <td>&mdash;</td>
<td>Three properties; <code>enabled</code> which toggles if fullscreen should be enabled (if the browser supports it). The default value is <code>true</code>. A <code>fallback</code> property which will enable a full window view for older browsers. The default value is <code>true</code>. A <code>hideControls</code> property which will hide the controls when fullscreen is active and the video is playing, after 1s. The controls reappear on hover of the progress bar (mouse), focusing a child control or pausing the video (by tap/click of video if `click` is `true`). The default value is <code>true</code>.</td> <td>See <a href="#fullscreen-options">below</a></td>
</tr> </tr>
<tr> <tr>
<td><code>storage</code></td> <td><code>storage</code></td>
@ -297,6 +297,45 @@ Options must be passed as an object to the `setup()` method as above.
</tbody> </tbody>
</table> </table>
#### Fullscreen options
<table class="table" width="100%" id="fullscreen-options">
<thead>
<tr>
<th width="20%">Option</th>
<th width="15%">Type</th>
<th width="15%">Default</th>
<th width="50%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>enabled</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Toggles if fullscreen should be enabled (if the browser supports it).</td>
</tr>
<tr>
<td><code>fallback</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Enable a full viewport view for older browsers.</td>
</tr>
<tr>
<td><code>hideControls</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Hide the controls when fullscreen is active and the video is playing, after 1s. The controls reappear on hover of the progress bar (mouse), focusing a child control or pausing the video (by tap/click of video if `click` is `true`).</td>
</tr>
<tr>
<td><code>allowAudio</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>Allow audio play to toggle fullscreen. This will be more useful later when posters are supported.</td>
</tr>
</tbody>
</table>
## API ## API
#### Fetching the plyr instance #### Fetching the plyr instance
@ -331,8 +370,8 @@ Here's a list of the methods supported:
<th width="15%">Parameters</th> <th width="15%">Parameters</th>
<th width="65%">Description</th> <th width="65%">Description</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><code>play()</code></td> <td><code>play()</code></td>
<td>&mdash;</td> <td>&mdash;</td>
@ -400,7 +439,7 @@ Here's a list of the methods supported:
</tr> </tr>
<tr> <tr>
<td><code>source(...)</code></td> <td><code>source(...)</code></td>
<td>String or Array</td> <td>Array</td>
<td> <td>
Set the media source. Set the media source.
<br><br> <br><br>
@ -434,6 +473,112 @@ Here's a list of the methods supported:
</tbody> </tbody>
</table> </table>
#### .source() method
This allows changing the plyr source and type on the fly.
Video example:
```javascript
player.source({
type: 'video',
title: 'Bug Buck Bunny',
sources: [{
src: 'https://cdn.selz.com/plyr/1.0/movie.mp4',
type: 'video/mp4'
},
{
src: 'https://cdn.selz.com/plyr/1.0/movie.webm',
type: 'video/webm'
}],
poster: 'https://cdn.selz.com/plyr/1.0/poster.jpg',
tracks: [{
kind: 'captions',
label: 'English',
srclang:'en',
src: 'https://cdn.selz.com/plyr/1.0/example_captions_en.vtt',
default: true
}]
});
```
Audio example:
```javascript
player.source({
type: 'audio',
title: '96 by Logistics',
sources: [{
src: 'https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3',
type: 'audio/mp3'
},
{
src: 'https://cdn.selz.com/plyr/1.0/logistics-96-sample.ogg',
type: 'audio/ogg'
}]
});
```
YouTube example:
```javascript
player.source({
type: 'youtube',
title: 'Enovato interview of Dan Cederholm for Made By',
sources: 'Au87oAJ2jeE'
});
```
Vimeo example
```javascript
player.source({
type: 'vimeo',
title: 'Yosemite HD II',
sources: '87701971'
});
```
Some more details on the object parameters
<table class="table" width="100%">
<thead>
<tr>
<th width="20%">Key</th>
<th width="15%">Type</th>
<th width="65%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>type</code></td>
<td>String</td>
<td>Options are <code>video</code>, <code>audio</code>, <code>youtube</code> and <code>vimeo</code></td>
</tr>
<tr>
<td><code>title</code></td>
<td>String</td>
<td>Title of the new media. Used for the aria labelling.</td>
</tr>
<tr>
<td><code>sources</code></td>
<td>Array or String</td>
<td>This is an array of sources or optionally a string for embedded players (YouTube and Vimeo). `type` is also optional for YouTube and Vimeo when specifying an array. For YouTube and Vimeo media, only the video ID must be passed as the source as shown above. The keys of this object are mapped directly to HTML attributes so more can be added to the object if required.</td>
</tr>
<tr>
<td><code>poster</code></td>
<td>String</td>
<td>URL for the poster image (video only).</td>
</tr>
<tr>
<td><code>tracks</code></td>
<td>Array</td>
<td>An array of track objects. Each element in the array is mapped directly to a track element and any keys mapped directly to HTML attributes so as in the example above, it will render as `<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.0/example_captions_en.vtt" default>`. Booleans are converted to HTML5 value-less attributes.</td>
</tr>
</tbody>
</table>
## Events/Callbacks ## Events/Callbacks
The `plyr` object on the player element also contains a `media` property which is a reference to the `<audio>` or `<video>` element within the player which you can use to listen for events. Here's an example: The `plyr` object on the player element also contains a `media` property which is a reference to the `<audio>` or `<video>` element within the player which you can use to listen for events. Here's an example:

View File

@ -78,7 +78,8 @@
fullscreen: { fullscreen: {
enabled: true, enabled: true,
fallback: true, fallback: true,
hideControls: true hideControls: true,
allowAudio: false
}, },
storage: { storage: {
enabled: true, enabled: true,
@ -664,7 +665,7 @@
time = typeof time === 'number' ? time : plyr.media.currentTime; time = typeof time === 'number' ? time : plyr.media.currentTime;
// If there's no subs available, bail // If there's no subs available, bail
if(!plyr.captions[plyr.subcount]) { if (!plyr.captions[plyr.subcount]) {
return; return;
} }
@ -930,9 +931,6 @@
_remove(containers[i]); _remove(containers[i]);
} }
// Set ID
container.setAttribute('id', id);
// Add embed class for responsive // Add embed class for responsive
_toggleClass(plyr.media, config.classes.videoWrapper, true); _toggleClass(plyr.media, config.classes.videoWrapper, true);
_toggleClass(plyr.media, config.classes.embedWrapper, true); _toggleClass(plyr.media, config.classes.embedWrapper, true);
@ -942,6 +940,9 @@
// Create the YouTube container // Create the YouTube container
plyr.media.appendChild(container); plyr.media.appendChild(container);
// Set ID
container.setAttribute('id', id);
// Setup API // Setup API
if (typeof YT === 'object') { if (typeof YT === 'object') {
_youTubeReady(videoId, container); _youTubeReady(videoId, container);
@ -984,7 +985,7 @@
// Wait for fragaloop load // Wait for fragaloop load
var timer = window.setInterval(function() { var timer = window.setInterval(function() {
if('$f' in window && iframe.loaded) { if ('$f' in window && iframe.loaded) {
window.clearInterval(timer); window.clearInterval(timer);
_vimeoReady.call(iframe); _vimeoReady.call(iframe);
@ -1122,11 +1123,11 @@
// Vimeo ready // Vimeo ready
function _vimeoReady() { function _vimeoReady() {
/* jshint validthis: true */ /* jshint validthis: true */
// Get the frame with fragaloop lib
plyr.embed = $f(this); plyr.embed = $f(this);
// Setup on ready // Setup on ready
plyr.embed.addEvent('ready', function() { plyr.embed.addEvent('ready', function() {
// Create a faux HTML5 API using the Vimeo API // Create a faux HTML5 API using the Vimeo API
plyr.media.play = function() { plyr.embed.api('play'); }; plyr.media.play = function() { plyr.embed.api('play'); };
plyr.media.pause = function() { plyr.embed.api('pause'); }; plyr.media.pause = function() { plyr.embed.api('pause'); };
@ -1178,13 +1179,13 @@
_triggerEvent(plyr.media, 'ended'); _triggerEvent(plyr.media, 'ended');
}); });
/*// Always seek to 0 // Always seek to 0
plyr.embed.api('seekTo', 0); //plyr.embed.api('seekTo', 0);
// Prevent autoplay if needed (seek will play) // Prevent autoplay if needed (seek will play)
if (!config.autoplay) { //if (!config.autoplay) {
plyr.embed.api('pause'); // plyr.embed.api('pause');
}*/ //}
}); });
} }
@ -1192,7 +1193,7 @@
function _setupCaptions() { function _setupCaptions() {
if (plyr.type === 'video') { if (plyr.type === 'video') {
// Inject the container // Inject the container
if(!_getElement(config.selectors.captions)) { if (!_getElement(config.selectors.captions)) {
plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"><span></span></div>'); plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"><span></span></div>');
} }
@ -1340,7 +1341,7 @@
// Setup fullscreen // Setup fullscreen
function _setupFullscreen() { function _setupFullscreen() {
if (plyr.type != 'audio' && config.fullscreen.enabled) { if ((plyr.type != 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
// Check for native support // Check for native support
var nativeSupport = fullscreen.supportsFullScreen; var nativeSupport = fullscreen.supportsFullScreen;
@ -1667,11 +1668,14 @@
show = (plyr.container.className.indexOf(config.classes.captions.active) === -1); show = (plyr.container.className.indexOf(config.classes.captions.active) === -1);
} }
// Set global
plyr.captionsEnabled = show;
// Toggle state // Toggle state
_toggleState(plyr.buttons.captions, show); _toggleState(plyr.buttons.captions, plyr.captionsEnabled);
// Add class hook // Add class hook
_toggleClass(plyr.container, config.classes.captions.active, show); _toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
} }
// Check if media is loading // Check if media is loading
@ -1753,7 +1757,7 @@
} }
// Fallback to 0 // Fallback to 0
if(isNaN(time)) { if (isNaN(time)) {
time = 0; time = 0;
} }
@ -1798,10 +1802,10 @@
// Add elements to HTML5 media (source, tracks, etc) // Add elements to HTML5 media (source, tracks, etc)
function _insertChildElements(type, attributes) { function _insertChildElements(type, attributes) {
if(typeof attributes === 'string') { if (typeof attributes === 'string') {
_insertElement(type, plyr.media, { src: attributes }); _insertElement(type, plyr.media, { src: attributes });
} }
else if(attributes.constructor === Array) { else if (attributes.constructor === Array) {
for (var i = attributes.length - 1; i >= 0; i--) { for (var i = attributes.length - 1; i >= 0; i--) {
_insertElement(type, plyr.media, attributes[i]); _insertElement(type, plyr.media, attributes[i]);
} }
@ -1811,7 +1815,7 @@
// Update source // Update source
// Sources are not checked for support so be careful // Sources are not checked for support so be careful
function _updateSource(source) { function _updateSource(source) {
if(typeof source === 'undefined') { if (typeof source === 'undefined') {
return; return;
} }
@ -1819,7 +1823,7 @@
_pause(); _pause();
// Clean up YouTube stuff // Clean up YouTube stuff
if(plyr.type === 'youtube') { if (plyr.type === 'youtube') {
// Destroy the embed instance // Destroy the embed instance
plyr.embed.destroy(); plyr.embed.destroy();
@ -1836,7 +1840,7 @@
_remove(plyr.media); _remove(plyr.media);
// Set the new type // Set the new type
if('type' in source && source.type !== plyr.type) { if ('type' in source && source.type !== plyr.type) {
plyr.type = source.type; plyr.type = source.type;
} }
@ -1853,7 +1857,7 @@
case 'youtube': case 'youtube':
case 'vimeo': case 'vimeo':
plyr.media = document.createElement('div'); plyr.media = document.createElement('div');
plyr.embedId = source.sources; plyr.embedId = (typeof source.sources === 'string' ? source.sources : source.sources[0].src);
break; break;
} }
@ -1861,8 +1865,8 @@
_prependChild(plyr.container, plyr.media); _prependChild(plyr.container, plyr.media);
// Set attributes for audio video // Set attributes for audio video
if(_inArray(config.types.html5, plyr.type)) { if (_inArray(config.types.html5, plyr.type)) {
if(config.crossorigin) { if (config.crossorigin) {
plyr.media.setAttribute('crossorigin', ''); plyr.media.setAttribute('crossorigin', '');
} }
if (config.autoplay) { if (config.autoplay) {
@ -1879,16 +1883,20 @@
// Classname reset // Classname reset
plyr.container.className = plyr.originalClassName; plyr.container.className = plyr.originalClassName;
// Restore class hooks
_toggleClass(plyr.container, config.classes.fullscreen.active, plyr.isFullscreen);
_toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
// Autoplay the new source? // Autoplay the new source?
config.autoplay = (source.autoplay || config.autoplay); config.autoplay = (source.autoplay || config.autoplay);
// Set media id for embeds // Set media id for embeds
if(_inArray(config.types.embed, plyr.type)) { if (_inArray(config.types.embed, plyr.type)) {
plyr.embedId = source.sources; plyr.embedId = source.sources;
} }
// Set new sources for html5 // Set new sources for html5
if(_inArray(config.types.html5, plyr.type)) { if (_inArray(config.types.html5, plyr.type)) {
_insertChildElements('source', source.sources); _insertChildElements('source', source.sources);
} }
@ -1899,13 +1907,13 @@
_mediaUpdated(); _mediaUpdated();
// HTML5 stuff // HTML5 stuff
if(_inArray(config.types.html5, plyr.type)) { if (_inArray(config.types.html5, plyr.type)) {
// Set volume // Set volume
_setVolume(); _setVolume();
_updateVolume(); _updateVolume();
// UI updates // UI updates
if(plyr.supported.full) { if (plyr.supported.full) {
// Reset time display // Reset time display
_timeUpdate(); _timeUpdate();
@ -1914,7 +1922,7 @@
} }
// Setup captions // Setup captions
if('tracks' in source) { if ('tracks' in source) {
_insertChildElements('track', source.tracks); _insertChildElements('track', source.tracks);
// Captions // Captions
@ -1930,7 +1938,7 @@
} }
} }
if('title' in source) { if ('title' in source) {
config.title = source.title; config.title = source.title;
_setupPlayAria(); _setupPlayAria();
} }
@ -2292,17 +2300,17 @@
// Select the elements // Select the elements
// Assume elements is a NodeList by default // Assume elements is a NodeList by default
if(typeof elements === 'string') { if (typeof elements === 'string') {
elements = document.querySelectorAll(elements); elements = document.querySelectorAll(elements);
} }
// Single HTMLElement passed // Single HTMLElement passed
else if(elements instanceof HTMLElement) { else if (elements instanceof HTMLElement) {
elements = [elements]; elements = [elements];
} }
// No selector passed, possibly options as first argument // No selector passed, possibly options as first argument
else if (!(elements instanceof NodeList) && typeof elements !== 'string') { else if (!(elements instanceof NodeList) && typeof elements !== 'string') {
// If options are the first argument // If options are the first argument
if(typeof options === 'undefined' && typeof elements === 'object') { if (typeof options === 'undefined' && typeof elements === 'object') {
options = elements; options = elements;
} }

View File

@ -32,10 +32,12 @@
// Tooltips // Tooltips
@tooltip-bg: @controls-bg; @tooltip-bg: @controls-bg;
@tooltip-border-color: @off-white; @tooltip-border-color: fade(@gray-dark, 10%);
@tooltip-border-width: 1px;
@tooltip-shadow: 0 0 5px @tooltip-border-color, 0 0 0 @tooltip-border-width @tooltip-border-color;
@tooltip-color: @control-color; @tooltip-color: @control-color;
@tooltip-padding: @control-spacing; @tooltip-padding: @control-spacing;
@tooltip-arrow-size: 5px; @tooltip-arrow-size: 6px;
@tooltip-radius: 3px; @tooltip-radius: 3px;
// Progress // Progress
@ -331,31 +333,44 @@
opacity: 0; opacity: 0;
background: @tooltip-bg; background: @tooltip-bg;
border: 1px solid @tooltip-border-color; box-shadow: @tooltip-shadow;
border-radius: @tooltip-radius; border-radius: @tooltip-radius;
color: @tooltip-color; color: @tooltip-color;
font-size: @font-size-small; font-size: @font-size-small;
line-height: 1.5; line-height: 1.5;
font-weight: 600; font-weight: 600;
transform: translate(-50%, (@tooltip-padding * 3)) scale(0); transform: translate(-50%, (@tooltip-padding * 3)) scale(.8);
transform-origin: 50% 100%; transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease; transition: transform .2s .1s ease, opacity .2s .1s ease;
// Arrow // Arrows
&::after { &::after,
&::before {
content: ''; content: '';
position: absolute; position: absolute;
z-index: 1; width: 0;
height: 0;
top: 100%; top: 100%;
left: 50%; left: 50%;
display: block; transform: translateX(-50%);
width: 10px; }
height: 10px; // The border triangle
background: @tooltip-bg; &::after {
transform: translate(-50%, -50%) rotate(45deg) translateY(1px); @border-arrow-size: (@tooltip-arrow-size + (@tooltip-border-width * 1));
border: 1px solid @tooltip-border-color; bottom: -(@border-arrow-size + @tooltip-border-width);
border-width: 0 1px 1px 0; border-right: @border-arrow-size solid transparent;
border-top: @border-arrow-size solid @tooltip-border-color;
border-left: @border-arrow-size solid transparent;
z-index: 1;
}
// The background triangle
&::before {
bottom: -@tooltip-arrow-size;
border-right: @tooltip-arrow-size solid transparent;
border-top: @tooltip-arrow-size solid @tooltip-bg;
border-left: @tooltip-arrow-size solid transparent;
z-index: 2;
} }
} }
button:hover .plyr-tooltip, button:hover .plyr-tooltip,

View File

@ -44,15 +44,18 @@ $control-color-hover: null !default;
// Tooltips // Tooltips
$tooltip-bg: $controls-bg !default; $tooltip-bg: $controls-bg !default;
$tooltip-border-color: transparentize(@gray-dark, .1) !default;
$tooltip-border-width: 1px;
$tooltip-shadow: 0 0 5px $tooltip-border-color, 0 0 0 $tooltip-border-width $tooltip-border-color;
$tooltip-color: $control-color !default; $tooltip-color: $control-color !default;
$tooltip-padding: $control-spacing !default; $tooltip-padding: $control-spacing !default;
$tooltip-arrow-size: 5px !default; $tooltip-arrow-size: 6px !default;
$tooltip-radius: 3px !default; $tooltip-radius: 3px !default;
// Progress // Progress
$progress-bg: rgba(red($gray), green($gray), blue($gray), .2) !default; $progress-bg: transparentize($gray, .2) !default;
$progress-playing-bg: $blue !default; $progress-playing-bg: $blue !default;
$progress-buffered-bg: rgba(red($gray), green($gray), blue($gray), .25) !default; $progress-buffered-bg: transparentize($gray, .25) !default;
$progress-loading-size: 40px !default; $progress-loading-size: 40px !default;
$progress-loading-bg: rgba(0,0,0, .15) !default; $progress-loading-bg: rgba(0,0,0, .15) !default;
@ -334,29 +337,44 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
opacity: 0; opacity: 0;
background: $tooltip-bg; background: $tooltip-bg;
box-shadow: $tooltip-shadow;
border-radius: $tooltip-radius; border-radius: $tooltip-radius;
color: $tooltip-color; color: $tooltip-color;
font-size: $font-size-small; font-size: $font-size-small;
line-height: 1.5; line-height: 1.5;
font-weight: 600; font-weight: 600;
transform: translate(-50%, ($tooltip-padding * 3)) scale(0); transform: translate(-50%, ($tooltip-padding * 3)) scale(.8);
transform-origin: 50% 100%; transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease; transition: transform .2s .1s ease, opacity .2s .1s ease;
&::after { // Arrows
&::after,
&::before {
content: ''; content: '';
display: block;
position: absolute; position: absolute;
left: 50%;
bottom: -$tooltip-arrow-size;
margin-left: -$tooltip-arrow-size;
width: 0; width: 0;
height: 0; height: 0;
transition: inherit; top: 100%;
border-style: solid; left: 50%;
border-width: $tooltip-arrow-size $tooltip-arrow-size 0 $tooltip-arrow-size; transform: translateX(-50%);
border-color: $controls-bg transparent transparent; }
// The border triangle
&::after {
$border-arrow-size: ($tooltip-arrow-size + ($tooltip-border-width * 1));
bottom: -($border-arrow-size + $tooltip-border-width);
border-right: $border-arrow-size solid transparent;
border-top: $border-arrow-size solid $tooltip-border-color;
border-left: $border-arrow-size solid transparent;
z-index: 1;
}
// The background triangle
&::before {
bottom: -$tooltip-arrow-size;
border-right: $tooltip-arrow-size solid transparent;
border-top: $tooltip-arrow-size solid $tooltip-bg;
border-left: $tooltip-arrow-size solid transparent;
z-index: 2;
} }
} }
button:hover .plyr-tooltip, button:hover .plyr-tooltip,