Ir para o conteúdo

CSS

O nosso CSS também não tem mistério. É um pouco extenso por conta da forma como este widget em particular funciona.

widget.css

:root{
    --ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
}

@font-face{
    font-family: 'condensed';
    src: url('../font/font-condensed.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

@font-face{
    font-family: 'light-condensed';
    src: url('../font/font-condensed-light.ttf') format('truetype');
    font-weight: lighter;
    font-style: normal;
}

html{
    font-size: 62.5% !important;
}

/*
 * Definições padrões.
 */

.widget{
    background: #c9d9f1;
    font-family: 'light-condensed';
    position: absolute;
    width: 100%;
    margin: auto;
    overflow: hidden;
    color: #fff;
    line-height: 1;
}

.widget .left{
    float: left;
}

.widget .clearfix:before,
.widget .clearfix:after{
    content: '';
    display: table;
}

.widget .clearfix:after{
    clear: both;
}

.widget .text-shadow{
    text-shadow: 0 .2rem .5rem #777;
}

.widget .p-l-20{
    padding-left: 2rem;
}

.widget .p-l-30{
    padding-left: 3rem;
}

.widget .p-l-50{
    padding-left: 5rem;
}

/*
 * Núvens do fundo.
 */

.widget .clouds{
    width: 100%;
    position: relative;
    z-index: 1;
}

.widget .clouds img{
    position: absolute;
    left: -100%;
    animation-name: animate-cloud;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    will-change: left;
}

.widget .clouds img:first-child{
    z-index: 2;
    animation-duration: 120s;
}

.widget .clouds img:first-child + img{
    margin-top: 20%;
    z-index: 1;
    animation-duration: 100s;
}

.widget .clouds img:first-child + img + img{
    margin-top: 20%;
    animation-duration: 60s;
    left: -40%;
}

/*
 * Tela principal.
 */

.widget .main{
    z-index: 3;
    max-height: 54rem;
    width: 100%;
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto;
}

.widget .main > *{
    height: 100%;
    opacity: 0;
}

.widget .main > div{
    width: auto;
    position: absolute;
    left: 16.5%;
    right: 16.5%;
    margin: auto;
    transition: all .5s var(--ease-out-cubic);
    will-change: opacity, left, right;
}

.widget .main > div > .infos{
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
    white-space: nowrap;
}

.widget .main aside{
    position: absolute;
    right: 0;
    transition: all .5s var(--ease-out-cubic) .2s;
    will-change: opacity, right;
}

.widget .main > div > .infos > div{
    display: inline-block;
    vertical-align: top;
}

.widget .main > div > .infos > div:first-child{
    -webkit-transform: scale(1.3);
    transform: scale(1.3);
    transition: transform .4s var(--ease-out-cubic);
    will-change: transform;
}

.widget .main > div > .infos > div:last-child{
    -webkit-transform: translateX(3rem);
    transform: translateX(3rem);
    opacity: 0;
    padding-top: 20rem;
    transition: all .6s var(--ease-out-cubic) .3s;
    will-change: transform, opacity;
}

.widget .main .infos p,
.widget .main .infos time{
    font-size: 3.7rem;
    font-weight: bold;
    line-height: 1;
    text-transform: uppercase;
    margin: 0 0 2rem;
    padding: 0;
}

.widget .main .infos time{
    font-size: 5.7em;
    margin-bottom: 4rem;
}

.widget .main .infos .city{
    font-family: 'condensed';
    font-size: 4.1rem;
    margin-bottom: 1rem;
}

.widget .main .infos .temperature{
    font-size: 9.1rem;
    line-height: .8;
    margin-left: -.7rem;
    padding-left: 8rem;
    background-image: url(../media/max.png);
    background-repeat: no-repeat;
    background-position: left center;
    position: relative;
}

.widget .main .infos .temperature.min{
    font-size: 8.7em;
    background-image: url(../media/min.png);
    margin-top: 4rem;
}

.widget .main .infos.mini{
    margin-bottom: 1.5rem;
    padding: 0 2rem;
}

.widget .main .infos.mini:first-child{
    margin-top: 1rem;
}

.widget .main .infos.mini > div + div{
    min-width: 19rem;
    overflow: hidden;
}

.widget .main .infos.mini .description{
    margin-top: 1rem;
}

.widget .main .infos.mini .temperature{
    font-size: 3.1rem;
    margin: 3rem 0 0;
    padding-left: 2rem;
    background-size: 2rem auto;
}

.widget .main .infos.mini .temperature:first-child{
    margin-right: 2rem;
}

.widget .main .infos.mini .temperature::after{
    content: '';
    display: none;
}

.widget .main .infos.mini time{
    font-family: 'condensed';
    font-size: 2.5rem;
    font-weight: normal;
    line-height: 1.5;
    margin: .5rem 0 0;
    display: block;
}

.widget .main aside{
    background: rgba(0, 0, 0, .6);
    border-radius: .4rem;
}

/*
 * Animações.
 */

@keyframes animate-cloud{
    to{
        left: 100%;
    }
}

.widget.animate-1 .main > div{
    opacity: 1;
}

.widget.animate-1 .main > div > .infos > div:first-child{
    -webkit-transform: scale(1);
    transform: scale(1);
}

.widget.animate-1 .main > div > .infos > div:last-child{
    -webkit-transform: translateX(0);
    transform: translateX(0);
    opacity: 1;
}

.widget.animate-2 .main > div{
    left: 0;
    right: 33%;
}

.widget.animate-2 .main aside{
    right: 3%;
    opacity: 1;
}

/*
 * Status do tempo.
 */

.widget .status{
    width: 54rem;
    height: 41rem;
    background-size: 100% !important;
}

.widget .status.mini{
    width: 16.8rem;
    height: 16.8rem;
}

.widget .status.chanceflurries{
    background: url(../media/0.png) no-repeat center;
}

.widget .status.chancerain{
    background: url(../media/1.png) no-repeat center;
}

.widget .status.chancesleat{
    background: url(../media/2.png) no-repeat center;
}

.widget .status.chancesnow{
    background: url(../media/3.png) no-repeat center;
}

.widget .status.chancetstorms{
    background: url(../media/4.png) no-repeat center;
}

.widget .status.clear{
    background: url(../media/5.png) no-repeat center;
}

.widget .status.cloudy{
    background: url(../media/6.png) no-repeat center;
}

.widget .status.flurries{
    background: url(../media/7.png) no-repeat center;
}

.widget .status.hazy{
    background: url(../media/8.png) no-repeat center;
}

.widget .status.mostlycloudy{
    background: url(../media/9.png) no-repeat center;
}

.widget .status.mostlysunny{
    background: url(../media/10.png) no-repeat center;
}

.widget .status.partlycloudy{
    background: url(../media/11.png) no-repeat center;
}

.widget .status.partlysunny{
    background: url(../media/12.png) no-repeat center;
}

.widget .status.rain{
    background: url(../media/13.png) no-repeat center;
}

.widget .status.sleet{
    background: url(../media/14.png) no-repeat center;
}

.widget .status.snow{
    background: url(../media/15.png) no-repeat center;
}

.widget .status.sunny{
    background: url(../media/16.png) no-repeat center;
}

.widget .status.tstorms{
    background: url(../media/17.png) no-repeat center;
}

.widget .status.unknown{
    background: url(../media/18.png) no-repeat center;
}

Uma nota sobre as animações

Nós precisamos ter um cuidado especial com as animações, por conta do poder de processamento limitado do hardware.

Em função disto, todas as animações são feitas com CSS. O Javascript deve ser usado apenas para manusear as classes que disparam as animações.

No nosso exemplo nós usamos as propriedades transition e animation para fazer as animações, aliadas à propriedade will-change que habilita o suporte a aceleração de hardware.

Dica

O uso de will-change é importante, mas também tem suas limitações. Há um excelente artigo no blog do Opera explicando tudo o que você precisa saber. Vale a leitura.

Próximo passo

Isso é tudo o que há para saber sobre o CSS dos widgets. Passando para a próxima etapa nós veremos a parte mais importante do widget: o Javascript.