Experimental football field rendered with CSS 3D transforms and using Velocity JS to handle animation.
Forked from anonymous/css-3d-football-field.markdown
Created
November 13, 2016 23:23
-
-
Save MaurizioCasciano/466c4c43dd735286a727cee8b04dcadf to your computer and use it in GitHub Desktop.
CSS 3D Football Field
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<main> | |
<div class="static"> | |
<h1 class="js-heading">Your Team</h1> | |
<p class="js-subheading">Experimental team line-up and football field using CSS 3D transforms.</p> | |
<div class="js-switcher switcher"> | |
<a href="#" class="js-switch disabled switch-btn">HOME</a><a href="#" class="js-switch switch-btn">AWAY</a> | |
</div> | |
</div> | |
<div class="js-stage stage texture"> | |
<div class="js-world world"> | |
<div class="team js-team"> | |
<!-- Team cards / icons goes here --> | |
</div> | |
<div class="terrain js-terrain"> | |
<div class="field field--alt"></div> | |
<div class="field ground"> | |
<div class="field__texture field__texture--gradient"></div> | |
<div class="field__texture field__texture--gradient-b"></div> | |
<div class="field__texture field__texture--grass"></div> | |
<div class="field__line field__line--goal"></div> | |
<div class="field__line field__line--goal field__line--goal--far"></div> | |
<div class="field__line field__line--outline"></div> | |
<div class="field__line field__line--penalty"></div> | |
<div class="field__line field__line--penalty-arc"></div> | |
<div class="field__line field__line--penalty-arc field__line--penalty-arc--far"></div> | |
<div class="field__line field__line--mid"></div> | |
<div class="field__line field__line--circle"></div> | |
<div class="field__line field__line--penalty field__line--penalty--far"></div> | |
</div> | |
<div class="field__side field__side--front"></div> | |
<div class="field__side field__side--left"></div> | |
<div class="field__side field__side--right"></div> | |
<div class="field__side field__side--back"></div> | |
</div> | |
</div> | |
<div class="loading js-loading">PLEASE WAIT...</div> | |
</div> | |
</main> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ASSET_URL = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/215059/' | |
$stage = null | |
$world = null | |
$terrain = null | |
$team = null | |
$teamListHome = null | |
$players = null | |
$playersHome = null # Subset of $players | |
$playersAway = null # Subset of $players | |
$switchBtn = null | |
$loadBtn = null | |
$closeBtn = null | |
$heading = null | |
$subHeading = null | |
$loading = null | |
$switcher = null | |
data = | |
players: | |
home: [ | |
{ name: 'Pizarro', asset: 'bm-pizarro.jpg', origin: 'Peru', height: '1.84m', shirt: '14', pos: 'Forward', dob: '36', goals: 1, games: 16, x: 110, y: -190 } | |
{ name: 'Robben', asset: 'bm-robben.png', origin: 'Holland', height: '1.80m', shirt: '10', pos: 'Forward', dob: '32', goals: 19, games: 30, x: -110, y: -190 } | |
{ name: 'Rilbery', asset: 'bm-rilbery.jpg', origin: 'France', height: '1.70m', shirt: '7', pos: 'Midfield', dob: '32', goals: 9, games: 22, x: 150, y: 50 } | |
{ name: 'Schweinsteiger', asset: 'bm-schweinsteiger.jpg', origin: 'Germany', height: '1.87m', shirt: '24', pos: 'Forward', dob: '31', goals: 21, games: 3, x: 0, y: 100 } | |
{ name: 'Martinez', asset: 'bm-martinez.jpg', origin: 'Spain', height: '1.90m', shirt: '8', pos: 'Midfield', dob: '28', goals: 0, games: 2, x: -150, y: 50 } | |
{ name: 'Alaba', asset: 'bm-alaba.jpg', origin: 'Austria', height: '1.80m', shirt: '27', pos: 'Defence', dob: '24', goals: 5, games: 27, x: -200, y: 180 } | |
{ name: 'Lahm', asset: 'bm-lahm.jpg', origin: 'Germany', height: '1.70', shirt: '21', pos: 'Defence', dob: '32', goals: 2, games: 25, x: 200, y: 180 } | |
{ name: 'Benatia', asset: 'bm-benatia.jpg', origin: 'France', height: '1.87m', shirt: '5', pos: 'Defence', dob: '31', goals: 21, games: 1, x: 100, y: 300 } | |
{ name: 'Dante', asset: 'bm-dante.jpg', origin: 'Brazil', height: '1.87m', shirt: '4', pos: 'Defence', dob: '32', goals: 0, games: 34, x: -100, y: 300 } | |
{ name: 'Neuer', asset: 'bm-neuer.jpg', origin: 'Germany', height: '1.93m', shirt: '1', pos: 'Goalie', dob: '29', goals: 0, games: 48, x: 0, y: 410 } | |
] | |
away: [ | |
{ name: 'Benzema', asset: 'rm-benzema.jpg', origin: 'France', height: '1.87m', shirt: '9', pos: 'Forward', dob: '36', goals: 1, games: 16, x: 110, y: -190 } | |
{ name: 'Bale', asset: 'rm-bale.jpg', origin: 'Wales', height: '1.83m', shirt: '11', pos: 'Midfield', dob: '26', goals: 19, games: 30, x: -110, y: -190 } | |
{ name: 'carvajal', asset: 'rm-carvajal.jpg', origin: 'Spain', height: '1.70m', shirt: '15', pos: 'Defender', dob: '32', goals: 9, games: 22, x: 150, y: 50 } | |
{ name: 'Silva', asset: 'rm-silva.jpg', origin: 'Brazil', height: '1.87m', shirt: '16', pos: 'Forward', dob: '22', goals: 21, games: 3, x: 0, y: 100 } | |
{ name: 'Kroos', asset: 'rm-kroos.jpg', origin: 'Germany', height: '1.82', shirt: '8', pos: 'Midfield', dob: '25', goals: 0, games: 2, x: -150, y: 50 } | |
{ name: 'Modric', asset: 'rm-modric.jpg', origin: 'Croatia', height: '1.74m', shirt: '19', pos: 'Midfield', dob: '30', goals: 5, games: 27, x: -200, y: 180 } | |
{ name: 'Nacho', asset: 'rm-nacho.jpg', origin: 'Germany', height: '1.79', shirt: '18', pos: 'Defence', dob: '25', goals: 2, games: 25, x: 200, y: 180 } | |
{ name: 'Ramos', asset: 'rm-ramos.jpg', origin: 'Spain', height: '1.83m', shirt: '4', pos: 'Defence', dob: '31', goals: 21, games: 1, x: 100, y: 300 } | |
{ name: 'Pepe', asset: 'rm-pepe.jpg', origin: 'Brazil', height: '1.88m', shirt: '3', pos: 'Defence', dob: '32', goals: 0, games: 34, x: -100, y: 300 } | |
{ name: 'Casillas', asset: 'rm-casillas.jpg', origin: 'Spain', height: '1.85m', shirt: '1', pos: 'Goalie', dob: '34', goals: 0, games: 48, x: 0, y: 410 } | |
] | |
state = | |
home: true | |
disabHover: false | |
swapSides: -> | |
if @home then @home = false else @home = true | |
curSide: -> | |
if @home then 'home' else 'away' | |
pos = | |
world: | |
baseX: 0 | |
baseY: 0 | |
baseZ: -200 | |
def: | |
goalie: [0,-50] | |
dom = | |
addPlayers: (side) -> | |
for key, val of data.players[side] | |
val.side= side | |
$el = @addPlayer val | |
$team.append $el | |
$players = $('.js-player') | |
$playersHome = $('.js-player[data-side="home"]') | |
$playersAway = $('.js-player[data-side="away"]') | |
addPlayer: (data) -> | |
$el = $ '<div class="js-player player" data-name="' + data.name + '" data-side="' + data.side + '" data-x="' + data.x + '" data-y="' + data.y + '"></div>' | |
$el.append '<div class="player__label"><span>' + data.name + '</span></div>' | |
$el.append '<div class="player__img"><img src= ' + ASSET_URL + data.asset + '></div>' | |
$el.prepend '<div class="player__card"> </div>' | |
$el.prepend '<div class="player__placeholder"></div>' | |
@populateCard $el.find('.player__card'), data | |
$el | |
preloadImages: (preload) -> | |
promises = [] | |
i = 0 | |
while i < preload.length | |
((url, promise) -> | |
img = new Image | |
img.onload = -> promise.resolve() | |
img.src = url | |
) preload[i], promises[i] = $.Deferred() | |
i++ | |
$.when.apply($, promises).done -> | |
scenes.endLoading() | |
scenes.loadIn(1600) | |
populateCard: ($el, data) -> | |
$el.append '<h3>' + data.name + '</h3>' + | |
'<ul class="player__card__list"><li><span>DOB</span><br/>' + data.dob + ' yr</li><li><span>Height</span><br/>' + data.height + '</li><li><span>Origin</span><br/>' + data.origin + '</li></ul>' + | |
'<ul class="player__card__list player__card__list--last"><li><span>Games</span><br/>' + data.games + '</li><li><span>Goals</span><br/>' + data.goals + '</li></ul>' | |
displayNone: ($el) -> | |
$el.css 'display', 'none' | |
events = | |
attachAll: -> | |
$switchBtn.on 'click', (e) -> | |
e.preventDefault() | |
$el = $(this) | |
return if $el.hasClass 'disabled' | |
scenes.switchSides() | |
$switchBtn.removeClass 'disabled' | |
$el.addClass 'disabled' | |
$loadBtn.on 'click', (e) -> | |
e.preventDefault() | |
scenes.loadIn() | |
$players.on 'click', (e) -> | |
e.preventDefault() | |
$el = $(this) | |
if $('.active').length then return false | |
$el.addClass 'active' | |
scenes.focusPlayer($el) | |
setTimeout ( -> events.attachClose()), 1 | |
attachClose: -> | |
$stage.one 'click', (e) -> | |
e.preventDefault() | |
scenes.unfocusPlayer() | |
scenes = | |
preLoad: -> | |
$teamListHome.velocity { opacity: 0 }, 0 | |
$players.velocity { opacity: 0 }, 0 | |
$loadBtn.velocity { opacity: 0 }, 0 | |
$switcher.velocity { opacity: 0 }, 0 | |
$heading.velocity { opacity: 0 }, 0 | |
$subHeading.velocity { opacity: 0 }, 0 | |
$playersAway.css 'display', 'none' | |
$world.velocity { opacity: 0, translateZ: -200, translateY: -60 }, 0 | |
$('main').velocity { opacity: 1 }, 0 | |
loadIn: (delay = 0) -> | |
$world.velocity { opacity: 1, translateY: 0, translateZ: -200 }, { duration: 1000, delay: delay, easing: 'spring' } | |
anim.fadeInDir($heading, 300, (delay + 600), 0, 30) | |
anim.fadeInDir($subHeading, 300, (delay + 800), 0, 30) | |
anim.fadeInDir($teamListHome, 300, (delay + 800), 0, 30) | |
anim.fadeInDir($switcher, 300, (delay + 900), 0, 30) | |
delay += 1200 | |
delayInc = 30 | |
anim.dropPlayers($playersHome, delay, delayInc) | |
startLoading: -> | |
anim.fadeInDir $loading, 300, 0, 0, -20 | |
images = [] | |
for key, val of data.players.home and data.players.away | |
images.push ASSET_URL + val.asset | |
dom.preloadImages(images) | |
endLoading: -> | |
anim.fadeOutDir $loading, 300, 1000, 0, -20 | |
arrangePlayers: -> | |
$players.each -> | |
$el = $(this) | |
$el.velocity | |
translateX: parseInt $el.attr('data-x') | |
translateZ: parseInt $el.attr('data-y') # Z is the Y axis on the field | |
focusPlayer: ($el) -> | |
data = $el.data() | |
shiftY = data.y | |
if shiftY > 0 then shiftY = (data.y / 2) | |
$('.js-player[data-side="' + state.curSide() + '"]').not('.active').each -> | |
$unfocus = $(this) | |
anim.fadeOutDir $unfocus, 300, 0, 0, 0, 0, null, 0.2 | |
$world.velocity | |
translateX: (pos.world.baseX - data.x) | |
translateY: (pos.world.baseY) | |
translateZ: (pos.world.baseZ - shiftY) # Z is the Y axis on the field | |
, 600 | |
$terrain.velocity | |
opacity: 0.66 | |
, 600 | |
@showPlayerCard $el, 600, 600 | |
unfocusPlayer: -> | |
$el = $('.js-player.active') | |
data = $el.data() | |
anim.fadeInDir $('.js-player[data-side="' + state.curSide() + '"]').not('.active'), 300, 300, 0, 0, 0, null, 0.2 | |
$el.removeClass 'active' | |
$world.velocity | |
translateX: (pos.world.baseX) | |
translateY: (pos.world.baseY) | |
translateZ: (pos.world.baseZ) # Z is the Y axis on the field | |
, 600 | |
$terrain.velocity | |
opacity: 1 | |
, 600 | |
@hidePlayerCard $el, 600, 600 | |
hidePlayerCard: ($el, dur, delay) -> | |
$card = $el.find '.player__card' | |
$image = $el.find '.player__img' | |
$image.velocity | |
translateY: 0 | |
, 300 | |
anim.fadeInDir $el.find '.player__label', 200, delay | |
anim.fadeOutDir $card, 300, 0, 0, -100 | |
showPlayerCard: ($el, dur, delay) -> | |
$card = $el.find '.player__card' | |
$image = $el.find '.player__img' | |
$image.velocity | |
translateY: '-=150px' | |
, 300 | |
anim.fadeOutDir $el.find '.player__label', 200, delay | |
anim.fadeInDir $card, 300, 200, 0, 100 | |
switchSides: -> | |
delay = 0 | |
delayInc = 20 | |
$old = $playersHome | |
$new = $playersAway | |
if !state.home | |
$old = $playersAway | |
$new = $playersHome | |
state.swapSides() | |
$old.each -> | |
$el = $(this) | |
anim.fadeOutDir($el, 200, delay, 0, -60, 0) | |
anim.fadeOutDir($el.find('.player__label'), 200, (delay + 700)) | |
delay += delayInc | |
$terrain.velocity { rotateY: '+=180deg' }, { delay: 150, duration: 1200 } | |
anim.dropPlayers($new, 1500, 30) | |
anim = | |
fadeInDir: ($el, dur, delay, deltaX = 0, deltaY = 0, deltaZ = 0, easing = null, opacity = 0) -> | |
$el.css 'display', 'block' | |
$el.velocity | |
translateX: '-=' + deltaX | |
translateY: '-=' + deltaY | |
translateZ: '-=' + deltaZ | |
, 0 | |
$el.velocity | |
opacity: 1 | |
translateX: '+=' + deltaX | |
translateY: '+=' + deltaY | |
translateZ: '+=' + deltaZ | |
, | |
easing: easing | |
delay: delay | |
duration: dur | |
fadeOutDir: ($el, dur, delay, deltaX = 0, deltaY = 0, deltaZ = 0, easing = null, opacity = 0) -> | |
if !opacity | |
display = 'none' | |
else | |
display = 'block' | |
$el.velocity | |
opacity: opacity | |
translateX: '+=' + deltaX | |
translateY: '+=' + deltaY | |
translateZ: '+=' + deltaZ | |
, | |
easing: easing | |
delay: delay | |
duration: dur | |
.velocity | |
opacity: opacity | |
translateX: '-=' + deltaX | |
translateY: '-=' + deltaY | |
translateZ: '-=' + deltaZ | |
, | |
duration: 0 | |
display: display | |
dropPlayers: ($els, delay, delayInc) -> | |
$els.each -> | |
$el = $(this) | |
$el.css | |
display : 'block' | |
opacity : 0 | |
anim.fadeInDir($el, 800, delay, 0, 50, 0, 'spring') | |
anim.fadeInDir($el.find('.player__label'), 200, (delay + 250)) | |
delay += delayInc | |
init = -> | |
$stage = $('.js-stage') | |
$world = $('.js-world') | |
$switchBtn = $('.js-switch') | |
$loadBtn = $('.js-load') | |
$heading = $('.js-heading') | |
$switcher = $('.js-switcher') | |
$closeBtn = $('.js-close') | |
$subHeading = $('.js-subheading') | |
$terrain = $('.js-terrain') | |
$team = $('.js-team') | |
$teamListHome = $('.js-team-home') | |
$loading = $('.js-loading') | |
dom.addPlayers('home') | |
dom.addPlayers('away') | |
scenes.preLoad() | |
scenes.arrangePlayers() | |
events.attachAll() | |
scenes.startLoading() | |
$(document).ready -> | |
init() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Palette | |
$body-bg-color = #2a437c | |
$body-bg-color-2 = #10203b | |
$colors-text-def = #333 | |
$colors-text-med = #777 | |
$colors-text-lt = #aaa | |
$colors-card-bg1 = #f7f7f7 | |
$colors-card-bg2 = #eeeeee | |
$colors-card-bg3 = #1d2643 | |
$colors-card-txt = #a40028 | |
$field-bg-color = #eeeeee | |
$field-side-color = #f7f7f7 | |
$line-color = rgba(255,255,255,0.5) | |
$texture-field-side = #141d2b | |
// Field dimensions | |
$stage-perspective = 1100px | |
$field-y = 840px | |
$field-x = ($field-y * 0.8) | |
$field-ratio = ($field-x / $field-y) | |
$field-side-y = 8px | |
$field-rot = 90deg | |
$field-buffer = 4% | |
$line-x = 3px | |
$line-circle-x = 25% | |
// Player dimensions | |
$player-x = 65px | |
$card-x = 230px | |
$card-y = 260px | |
// Codepen asset mixin | |
asset(filename='blank.gif') | |
background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/215059/' filename) | |
* | |
box-sizing: border-box | |
html, body | |
width: 100% | |
height: 100% | |
font-size: 62.5% | |
padding: 0 | |
margin: 0 | |
.velocity-animating | |
transition: none !important | |
body | |
background-image: -webkit-radial-gradient(ellipse, $body-bg-color 0, $body-bg-color-2 100%) | |
font-family: 'Open Sans', helvetica, arial, sans-serif | |
main | |
opacity: 0 | |
.static | |
position: absolute | |
top: 0 | |
left: 0 | |
width: 100% | |
color: #fff | |
text-align: center | |
padding: 0 | |
z-index: 3 | |
h1 | |
margin: 50px 0 15px | |
font-size: 50px | |
font-weight: 800 | |
text-transform: uppercase | |
line-height: 42px | |
letter-spacing: -3px | |
font-family: montserrat | |
p | |
font-weight: 300 | |
opacity: 0.4 | |
margin: 0 0 20px | |
font-size: 16px | |
color: lighten($body-bg-color, 50%) | |
.loading | |
position: absolute | |
top: 0 | |
right: 0 | |
bottom: 0 | |
left: 0 | |
margin: auto | |
height: 16px | |
line-height: 16px | |
color: #fff | |
font-family: 'montserrat' | |
font-size: 24px | |
font-weight: 900 | |
letter-spacing: -1px | |
text-align: center | |
opacity: 0 | |
.team-list | |
position: absolute | |
left: 40px | |
top: 100px | |
list-style: none | |
display: none | |
li:first-child | |
color: #fff | |
font-weight: bold | |
li | |
font-size: 1.4rem | |
margin: 0 0 10px | |
color: lighten($body-bg-color, 50%) | |
.stage | |
position: absolute | |
width: 100% | |
height: 100% | |
top: 0 | |
perspective-origin: 50% -200px | |
perspective: $stage-perspective | |
z-index: 1 | |
backface-visibility: hidden | |
.world | |
position: absolute | |
top: 130px | |
left: 50% | |
margin-left: -($field-x / 2) | |
width: $field-x | |
height: $field-y | |
transform: translateZ(-($field-y / 4)) | |
transform-style: preserve-3d | |
z-index: 1 | |
backface-visibility: hidden | |
&.flipped | |
transform: translateZ(-($field-y / 4)) rotateY(180deg) | |
&.switched | |
transform: translateZ(250px) rotateY(30deg) translateX(60px) translateY(-200px) | |
.switch-btn | |
display: inline-block | |
padding: 6px 15px | |
border: solid 1px lighten($body-bg-color, 50%) | |
border-radius: 5px | |
text-align: center | |
color: lighten($body-bg-color, 50%) | |
text-decoration: none | |
opacity: 1 | |
font-size: 12px | |
transition: all 0.15s | |
&.disabled | |
background: lighten($body-bg-color, 50%) | |
color: $body-bg-color | |
cursor: default | |
&:hover | |
color: $body-bg-color | |
&:hover | |
color: #fff | |
&:first-child | |
border-radius: 10px 0 0 10px | |
border-right: none | |
&:last-child | |
border-radius: 0 10px 10px 0 | |
.team | |
position: absolute | |
top: 0 | |
left: 0 | |
width: 100% | |
height: 100% | |
transform-style: preserve-3d | |
.terrain | |
position: absolute | |
top: 0 | |
left: 0 | |
width: 100% | |
height: 100% | |
transform-style: inherit | |
.field | |
position: absolute | |
top: 0 | |
left: 0 | |
width: 100% | |
height: 100% | |
background-color: $field-bg-color | |
z-index: 2 | |
transform: rotateX($field-rot) translateZ(0) | |
transform-origin: 50% 50% | |
box-sizing: content-box | |
backface-visibility: hidden | |
.field--alt | |
display: block | |
width: 80% | |
left: 10% | |
transform: rotateX($field-rot) translateZ(-10px) | |
background: black | |
opacity: 0.3 | |
box-shadow: 0 0 40px 30px #000 | |
.field__texture | |
width: 100% | |
height: 100% | |
position: absolute | |
z-index: 3 | |
&.field__texture--gradient | |
background-image: linear-gradient(to top, rgba(0,0,0,0.2), transparent) | |
z-index: 4 | |
.flipped & | |
opacity: 0 | |
&.field__texture--gradient-b | |
opacity: 0 | |
background-image: linear-gradient(to bottom, rgba(0,0,0,0.2), transparent) | |
z-index: 4 | |
.flipped & | |
opacity: 1 | |
.texture & | |
&.field__texture--grass | |
asset('grass2.png') | |
background-repeat: repeat | |
background-size: 75px 75px | |
background-position: -20px -20px | |
.field__side | |
position: absolute | |
top: ($field-y / 2) | |
left: 0 | |
width: 100% | |
height: $field-side-y | |
transform: rotateX($field-rot * 2) translateZ(-($field-y / 2)) | |
transform-origin: 50% 50% | |
background-color: $field-side-color | |
z-index: 9 | |
.texture & | |
background-color: black | |
&:after | |
content: "" | |
top: 0 | |
left: 0 | |
bottom: 0 | |
right: 0 | |
position: absolute | |
opacity: 0.55 | |
asset('mud.png') | |
background-repeat: repeat | |
background-size: 75px 75px | |
background-position: -20px -20px | |
&.field__side--left, | |
&.field__side--right | |
top: 0 | |
left: -($field-side-y) | |
height: 100% | |
width: $field-side-y | |
transform-origin: 100% 50% | |
transform: rotateX($field-rot) rotateY(-90deg) translateZ(0) | |
&.field__side--right | |
left: auto | |
right: 0 | |
&.field__side--back | |
transform: rotateX($field-rot * 2) translateZ(($field-y / 2)) | |
.field__line | |
position: absolute | |
width: 100% | |
height: $line-x | |
z-index: 4 | |
.field__line--goal | |
width: 16% | |
height: 6% | |
border: solid $line-x $line-color | |
border-bottom: none | |
left: 0 | |
right: 0 | |
margin: auto | |
bottom: $field-buffer | |
.field__line--goal--far | |
top: $field-buffer | |
bottom: auto | |
border: solid $line-x $line-color | |
border-top: none | |
.field__line--penalty-arc | |
width: 20% | |
height: 20% | |
overflow: hidden | |
bottom: ($field-buffer + 16%) | |
left: 0 | |
right: 0 | |
margin: auto | |
&:after | |
position: absolute | |
top: 75% | |
width: 100% | |
height: 100% | |
left: 0 | |
content: ' ' | |
display: block | |
border-radius: 50% 50% 0 0 | |
border: solid $line-x $line-color | |
border-bottom: none | |
box-sizing: border-box | |
.field__line--penalty-arc--far | |
bottom: auto | |
top: ($field-buffer + 16%) | |
&:after | |
bottom: 75% | |
top: auto | |
border: solid $line-x $line-color | |
border-top: none | |
border-radius: 0 0 50% 50% | |
.field__line--penalty | |
width: 44% | |
height: 16% | |
border: solid $line-x $line-color | |
border-bottom: none | |
left: 0 | |
right: 0 | |
margin: auto | |
bottom: $field-buffer | |
.field__line--penalty--far | |
top: $field-buffer | |
bottom: auto | |
border: solid $line-x $line-color | |
border-top: none | |
.field__line--outline | |
width: (100% - ($field-buffer * 2)) | |
height: (100% - ($field-buffer * 2)) | |
top: $field-buffer | |
left: $field-buffer | |
border: solid $line-x $line-color | |
.field__line--mid | |
top: 50% | |
width: (100% - ($field-buffer * 2)) | |
left: $field-buffer | |
background-color: $line-color | |
.field__line--circle | |
width: 20% | |
height: 20% | |
top: 0 | |
left: 0 | |
right: 0 | |
bottom: 0 | |
margin: auto | |
border: solid $line-x $line-color | |
border-radius: 50% | |
.debug-btn | |
position: absolute | |
right: 40px | |
top: 40px | |
border: solid 1px #fff | |
border-radius: 10px | |
height: 20px | |
padding: 0 10px | |
color: #fff | |
text-decoration: none | |
line-height: 20px | |
&:hover | |
opacity: 1 | |
background-color: rgba(255, 255, 255, 0.1) | |
&.debug-btn--load | |
top: 80px | |
.player | |
position: absolute | |
height: $player-x + 23px | |
width: $player-x | |
padding-bottom: 23px | |
z-index: 9 | |
left: 50% | |
margin-left: -($player-x / 2) | |
bottom: 50% | |
transform-style: preserve-3d | |
backface-visibility: hidden | |
transition: all 0.2s | |
cursor: pointer | |
.player__placeholder | |
position: absolute | |
opacity: 0 | |
transform: rotateX(90deg) | |
height: 30px | |
width: 30px | |
bottom: -10px | |
left: 0 | |
right: 0 | |
margin: auto | |
border-radius: 50% | |
background-color: rgba(0, 0, 0, 0.2) | |
z-index: 1 | |
&.active | |
.player__placeholder | |
opacity: 1 | |
.player__card | |
position: absolute | |
bottom: 26px | |
left: (($player-x / 2) - ($card-x / 2)) | |
height: $card-y | |
background-color: $colors-card-bg1 | |
opacity: 0 | |
width: $card-x | |
padding: 0 | |
font-size: 18px | |
color: #333 | |
border-radius: 4px | |
z-index: 2 | |
//overflow: hidden | |
&:after | |
position: absolute | |
display: block | |
content: '' | |
height: 1px | |
width: 1px | |
border: solid 10px transparent | |
border-top: solid 10px $colors-card-bg2 | |
bottom: -21px | |
left: 0 | |
right: 0 | |
margin: auto | |
top: auto | |
z-index: 3 | |
i | |
position: absolute | |
top: 0px | |
right: 0px | |
padding: 10px 15px | |
font-size: 24px | |
line-height: 20px | |
color: white | |
opacity: 0.3 | |
cursor: pointer | |
transition: all 0.15s | |
&:hover | |
opacity: 0.6 | |
h3 | |
text-align: center | |
font-weight: normal | |
text-transform: uppercase | |
font-family: montserrat | |
font-size: 19px | |
line-height: 27px | |
color: $colors-text-def | |
color: white | |
padding: 15px 30px 40px | |
margin: 0 0 30px | |
background-color: #eee | |
border-radius: 4px 4px 0 0 | |
background-color: desaturate(darken($body-bg-color, 45%), 10%) | |
span:first-child | |
display: inline-block | |
height: 27px | |
width: 27px | |
border-radius: 50% | |
border: solid 1px #fff | |
line-height: 27px | |
opacity: 0.4 | |
font-size: 18px | |
span:last-child | |
font-size: 14px | |
opacity: 0.4 | |
p | |
color: $colors-text-med | |
font-syle: italic | |
text-align: center | |
.player__card__list | |
padding: 10px 0 | |
font-size: 14px | |
color: $colors-text-med | |
overflow: auto | |
text-align: center | |
li | |
display: inline-block | |
white-space: nowrap | |
text-overflow: ellipsis | |
text-align: center | |
font-size: 15px | |
padding-left: 20px | |
color: $colors-text-def | |
//border-left: solid 1px #ddd | |
span | |
font-size: 12px | |
text-transform: uppercase | |
color: $colors-text-lt | |
&:first-child | |
padding-left: 0 | |
border-left: none | |
.player__card__list--last | |
position: absolute | |
width: 100% | |
bottom: 0 | |
background-color: $colors-card-bg2 | |
margin: 0 | |
padding: 0 | |
border-top: solid 1px #ddd | |
border-radius: 0 0 6px 6px | |
overflow: hidden | |
li | |
width: 50% | |
padding: 10px 0 20px 0 | |
color: $colors-card-txt | |
font-size: 28px | |
line-height: 22px | |
&:last-child | |
border-left: solid 1px #ddd | |
* | |
pointer-events: none | |
.player__img | |
position: absolute | |
top: 0 | |
left: 0 | |
width: $player-x | |
height: $player-x | |
z-index: 4 | |
overflow: hidden | |
border-radius: ($player-x / 2) | |
background-color: #000 | |
border: solid 1px #fff | |
backface-visibility: hidden | |
transition: all 0.2s | |
img | |
width: 100% | |
transition: all 0.2s | |
display: block | |
.player__label | |
position: absolute | |
height: 20px | |
display: inline-block | |
width: auto | |
overflow: visible | |
white-space: nowrap | |
left: -100% | |
right: -100% | |
margin: auto | |
padding: 0 10px | |
line-height: 20px | |
text-align: center | |
border-radius: 10px | |
bottom: 0 | |
opacity: 0 | |
text-transform: upppercase | |
transition: opacity 0.2s | |
z-index: 2 | |
pointer-events: none | |
span | |
background-color: rgba(16, 20, 30, 0.9) | |
color: white | |
font-size: 11px | |
padding: 3px 10px 2px 10px | |
border-radius: 10px | |
text-transform: upppercase | |
&:hover | |
.player__img | |
opacity: 1 | |
.player__label | |
opacity: 1 | |
.texture & | |
background-size: 100% auto | |
// @keyframes spinner | |
// to | |
// transform rotate(360deg) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Free to use?