Another Dribbble rework of an original shot by Sergey Valiukh. Chrome and Safari only, for now.
A Pen by David Khourshid on CodePen.
Another Dribbble rework of an original shot by Sergey Valiukh. Chrome and Safari only, for now.
A Pen by David Khourshid on CodePen.
| <main> | |
| <div class="device"> | |
| <header> | |
| <div class="header-bar"></div> | |
| <div class="header-title"> | |
| <h1>Calendar</h1> | |
| </div> | |
| <div class="header-weekdays"> | |
| <span>sun</span> | |
| <span>mon</span> | |
| <span>tue</span> | |
| <span>wed</span> | |
| <span>thu</span> | |
| <span>fri</span> | |
| <span>sat</span> | |
| </div> | |
| </header> | |
| <section> | |
| <h2 class="month">December</h2> | |
| <form> | |
| <input type="radio" name="calendar-label-bg" class="calendar-label-bg" id="vacation" /> | |
| <input type="radio" name="calendar-label-bg" class="calendar-label-bg" id="walk" /> | |
| <input type="radio" name="calendar-label-bg" class="calendar-label-bg" id="fishing" /> | |
| <input type="radio" name="calendar-label-bg" class="calendar-label-bg" id="weekend" /> | |
| <input type="radio" name="calendar-label-bg" id="new" class="calendar-label-bg"> | |
| <div class="calendar"> | |
| <input type="checkbox" name="" id="" class="day previous-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day current-month" /> | |
| <input type="checkbox" name="" id="" class="day next-month" /> | |
| <input type="checkbox" name="" id="" class="day next-month" /> | |
| <input type="checkbox" name="" id="" class="day next-month" /> | |
| <div class="calendar-labels"> | |
| <label for="vacation"><span>vacation</span></label> | |
| <label for="walk"><span>walk</span></label> | |
| <label for="fishing"><span>fishing</span></label> | |
| <label for="weekend"><span>weekend</span></label> | |
| <label for="new" class="full"><input type="text" placeholder="Add new task"></label> | |
| <label class="reset"> | |
| <input type="reset" value="Reset"/> | |
| </label> | |
| </div> | |
| </div> | |
| </form> | |
| <h2 class="month">January</h2> | |
| <div class="calendar inactive"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| <input type="checkbox" name="" id="" class="day next-month"> | |
| </div> | |
| </section> | |
| </div> | |
| </main> | |
| <aside> | |
| <div class="meta"> | |
| <h1>CSS-only Calendar App Concept</h1> | |
| <p> | |
| Dribbble Rework<br> | |
| Original shot by <a href="https://dribbble.com/shots/1841134-Gif-for-Calendar">Sergey Valiukh</a> | |
| </p> | |
| <p> | |
| Click two dates and the labels to see the effect.<br> | |
| Works <strike>best</strike> only in Chrome and Safari. | |
| </p> | |
| </div> | |
| </aside> |
| // I promise that I know JavaScript. | |
| // Currently only works in Chrome. | |
| // Firefox doesn't like custom inputs. | |
| // @davidkpiano |
| <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script> |
| @import "compass/css3"; | |
| @import url(http://fonts.googleapis.com/css?family=Lato:300,400,700); | |
| $device-width: 264px * 1.5; | |
| $device-height: 544px * 1.5; | |
| $color-bg: #4075b7; | |
| $color-app: white; | |
| $color-header: #58b2a4; | |
| $color-device: #dcdfe6; | |
| $color-device-border: white; | |
| $color-device-part: #a1a5b3; | |
| $color-text-dark: #333; | |
| $color-text-light: white; | |
| $color-noncurrent-month: rgba($color-text-dark, 0.3); | |
| $color-check: rgba(white, 0.7); | |
| $color-vacation: #d3738b; | |
| $color-fishing: #8f658a; | |
| $color-walk: #7186db; | |
| $color-weekend: #f7c187; | |
| $color-new: $color-header; | |
| $colors: ( | |
| vacation: $color-vacation, | |
| fishing: $color-fishing, | |
| walk: $color-walk, | |
| weekend: $color-weekend, | |
| new: $color-new | |
| ); | |
| $day-height: 3rem; | |
| $day-labels: (vacation, fishing, walk, weekend, new); | |
| $animation-easing: cubic-bezier(0.77, 0, 0.175, 1); | |
| $label-speed: 1s; | |
| $day-speed: 0.6s; | |
| $bg-speed: 1s; | |
| $header-height: $day-height * 2; | |
| @mixin range($min, $max) { | |
| &:nth-child(n + #{$min}):nth-child(-n + #{$max}) { | |
| @content; | |
| } | |
| } | |
| @mixin clearfix { | |
| &:before, &:after { | |
| content: " "; | |
| display: table; | |
| } | |
| &:after { clear: both; } | |
| } | |
| @function day-span($days) { | |
| @return percentage($days / 7); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| position: relative; | |
| } | |
| html, body { | |
| font-family: Lato, sans-serif; | |
| font-weight: 300; | |
| line-height: 1; | |
| background-color: $color-bg; | |
| width: 100%; | |
| height: 100%; | |
| counter-reset: previous-month 29 current-month next-month; | |
| margin: 0; | |
| } | |
| aside, main { | |
| width: 50%; | |
| height: $device-height; | |
| float: left; | |
| padding: 0 2rem; | |
| margin: 2rem 0; | |
| } | |
| header { | |
| color: $color-text-light; | |
| } | |
| .header-bar { | |
| height: 1rem; | |
| } | |
| .header-title { | |
| padding: 1rem; | |
| h1 { | |
| font-weight: 300; | |
| font-size: 1rem; | |
| margin: 0; | |
| padding: 0; | |
| text-align: center; | |
| text-transform: uppercase; | |
| letter-spacing: 3px; | |
| } | |
| } | |
| .header-weekdays { | |
| height: 2rem; | |
| span { | |
| font-size: 0.8rem; | |
| display: block; | |
| float: left; | |
| width: percentage(1/7); | |
| padding: 0.5rem 0; | |
| text-align: center; | |
| text-transform: uppercase; | |
| } | |
| } | |
| .calendar { | |
| @include clearfix(); | |
| &.inactive { | |
| pointer-events: none; | |
| } | |
| } | |
| form { | |
| @include clearfix(); | |
| background: rgba($color-header, 0.9); | |
| } | |
| .month { | |
| padding: 1rem; | |
| font-size: 1rem; | |
| color: $color-text-dark; | |
| margin: 0; | |
| } | |
| .day { | |
| float: left; | |
| width: percentage(1/7); | |
| text-align: center; | |
| padding: 1rem 0; | |
| margin: 0; | |
| font-size: 1rem; | |
| line-height: 1; | |
| -webkit-appearance: none; | |
| appearance: none; | |
| outline: none; | |
| transition-property: background, color; | |
| transition-duration: 0.3s; | |
| transition-timing-function: ease-in-out; | |
| transition-delay: 0s; | |
| .device:not(:hover) & { transition-duration: 0; } | |
| &:after { | |
| display: block; | |
| transition-property: transform, opacity; | |
| transition-duration: $day-speed; | |
| transition-timing-function: $animation-easing; | |
| } | |
| &.current-month:after { | |
| content: counter(current-month); | |
| counter-increment: current-month; | |
| } | |
| &.next-month:after { | |
| content: counter(next-month); | |
| counter-increment: next-month; | |
| } | |
| &.previous-month:after { | |
| content: counter(previous-month); | |
| counter-increment: previous-month; | |
| } | |
| &.previous-month, &.next-month { | |
| color: $color-noncurrent-month; | |
| } | |
| &:last-of-type:before { | |
| content: ''; | |
| display: block; | |
| position: absolute; | |
| top: 0; | |
| left: 100%; | |
| width: 700%; | |
| height: 100%; | |
| background: $color-app; | |
| } | |
| &:checked { | |
| &, & ~ .day { | |
| color: $color-text-light; | |
| } | |
| & ~ .day { | |
| background-color: transparent; | |
| } | |
| } | |
| &:hover, | |
| &:checked, | |
| & ~ .day:hover, | |
| & ~ .day:checked { | |
| background-color: rgba(0, 0, 0, 0.1); | |
| color: $color-text-light; | |
| } | |
| &, &:checked ~ .day:checked ~ .day, | |
| &:checked ~ .day:hover ~ .day, | |
| &:checked:hover ~ .day { | |
| background-color: $color-app; | |
| color: $color-text-dark; | |
| &.next-month { color: $color-noncurrent-month; } | |
| } | |
| @for $day from 1 through 7 { | |
| &:nth-child(7n + #{$day}):after { | |
| transition-delay: (1/7) * ($day - 1) * $day-speed; | |
| animation-delay: (1/7) * ($day - 1) * $day-speed; | |
| } | |
| } | |
| } | |
| .calendar-label-bg { | |
| display: block; | |
| position: absolute; | |
| outline: none; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 5 * $day-height; | |
| margin: 0; | |
| -webkit-appearance: none; | |
| appearance: none; | |
| transform: translateX(-100%); | |
| animation: bg-inactive $bg-speed $animation-easing; | |
| &:checked { | |
| animation: bg-active $bg-speed $animation-easing forwards; | |
| ~ .calendar .day:checked { | |
| &:after, & ~ .day:after { | |
| animation-name: day-active; | |
| animation-duration: $day-speed; | |
| animation-timing-function: $animation-easing; | |
| } | |
| & ~ .day:checked ~ .day:after { | |
| animation: none; | |
| } | |
| } | |
| } | |
| } | |
| @each $label in $day-labels { | |
| $label-color: map-get($colors, $label); | |
| ##{$label} { background-color: $label-color; } | |
| ##{$label}:checked { | |
| ~ .calendar { | |
| @for $weekday from 1 through 7 { | |
| .day { | |
| &:nth-child(7n + #{$weekday}) { | |
| z-index: (8 - $weekday) * 10; | |
| } | |
| } | |
| } | |
| .calendar-labels label[for=#{$label}] { | |
| &:not(.full):before { | |
| visibility: visible; | |
| animation: check-active 0.1s 0.2s ease-out both; | |
| } | |
| &.full { | |
| input { font-weight: 700; } | |
| &:before { | |
| color: $color-text-light; | |
| border-color: $color-text-light; | |
| } | |
| } | |
| > span { | |
| transform: translateX(2rem); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| .calendar-labels { | |
| display: none; | |
| width: 100%; | |
| position: absolute; | |
| top: 0; | |
| z-index: 100; | |
| pointer-events: none; | |
| transition: all 0s ease-in-out; | |
| transition-delay: $label-speed; | |
| transform: translateY(0); | |
| opacity: 0; | |
| .device:hover & { display: block; } | |
| &:before { | |
| content: ''; | |
| display: block; | |
| position: absolute; | |
| bottom: 100%; | |
| height: 5 * $day-height; | |
| width: 100%; | |
| pointer-events: auto; | |
| } | |
| > label { | |
| display: block; | |
| float: left; | |
| width: day-span(4); | |
| font-size: 1rem; | |
| padding: 1rem; | |
| color: $color-text-light; | |
| font-weight: 700; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| &:before { | |
| display: block; | |
| position: absolute; | |
| left: 0.75rem; | |
| height: 1rem; | |
| visibility: hidden; | |
| } | |
| &.full { | |
| width: 100%; | |
| font-weight: 700; | |
| &:before { | |
| transition-property: color, border-color; | |
| transition-duration: 0.3s; | |
| transition-timing-function: ease-in-out; | |
| content: '+'; | |
| top: calc(50% - 0.75rem); | |
| font-size: 1rem; | |
| font-weight: 700; | |
| width: 1rem; | |
| border: 4px solid $color-check; | |
| color: $color-check; | |
| border-radius: 50%; | |
| text-align: center; | |
| visibility: visible; | |
| } | |
| > input { | |
| display: block; | |
| margin-left: 2rem; | |
| width: calc(100% - 2rem); | |
| font-size: 1rem; | |
| background-image: none; | |
| background-color: transparent; | |
| outline: none; | |
| border: none; | |
| color: $color-text-light; | |
| line-height: 1; | |
| padding: 0; | |
| &::placeholder { | |
| color: $color-check; | |
| } | |
| } | |
| } | |
| &.reset { | |
| width: 100%; | |
| background: $color-app; | |
| float: left; | |
| padding: 0; | |
| height: 3rem; | |
| > input { | |
| display: block; | |
| padding: 1rem; | |
| line-height: 1; | |
| font-size: 0.8rem; | |
| width: 100%; | |
| height: 100%; | |
| -webkit-appearance: none; | |
| border: none; | |
| background: transparent; | |
| outline: none; | |
| text-transform: uppercase; | |
| color: $color-noncurrent-month; | |
| letter-spacing: 3px; | |
| } | |
| } | |
| &:not(.full):before { | |
| content: ''; | |
| top: 50%; | |
| width: 0.5rem; | |
| transform: scaleX(-1) rotate(135deg); | |
| transform-origin: left top; | |
| border-right: 5px solid $color-check; | |
| border-top: 5px solid $color-check; | |
| animation: check-inactive 0.3s 0 $animation-easing both; | |
| } | |
| > * { | |
| transition: transform 0.3s $animation-easing; | |
| display: inline-block; | |
| } | |
| @each $label in $day-labels { | |
| &[for="#{$label}"] { | |
| background: map-get($colors, $label); | |
| } | |
| } | |
| @include range(2, 3) { | |
| width: day-span(3); | |
| } | |
| animation-duration: $label-speed; | |
| animation-timing-function: $animation-easing; | |
| animation-fill-mode: both; | |
| &:nth-child(2n - 1) { | |
| z-index: 20; | |
| animation-name: leftLabel-inactive; | |
| } | |
| &:nth-child(2n) { | |
| z-index: 10; | |
| animation-name: rightLabel-inactive; | |
| } | |
| } | |
| } | |
| .day:checked ~ .day:checked { | |
| ~ .calendar-labels { | |
| transition-delay: 0s; | |
| display: block; | |
| opacity: 1; | |
| } | |
| @for $week from 1 through 5 { | |
| @include range(($week - 1) * 7 + 1, $week * 7) { | |
| ~ .calendar-labels { | |
| transform: translateY($week * $day-height); | |
| pointer-events: auto; | |
| } | |
| } | |
| } | |
| ~ .day:nth-child(7n) ~ .day, | |
| &:nth-child(7n) ~ .day { | |
| &:after { | |
| transform: translateY(5 * $day-height); | |
| opacity: 0; | |
| } | |
| } | |
| ~ .calendar-labels { | |
| label:nth-child(2n - 1) { | |
| z-index: 20; | |
| animation: leftLabel-active $label-speed $animation-easing both; | |
| } | |
| label:nth-child(2n) { | |
| z-index: 10; | |
| animation: rightLabel-active $label-speed $animation-easing both; | |
| } | |
| } | |
| } | |
| @keyframes check-active { | |
| 0% { | |
| width: 0; | |
| height: 0; | |
| opacity: 0; | |
| } | |
| 50% { | |
| opacity: 1; | |
| width: 0.5rem; | |
| height: 0; | |
| } | |
| 100% { | |
| opacity: 1; | |
| } | |
| } | |
| @keyframes check-inactive { | |
| 50% { | |
| opacity: 1; | |
| width: 0.5rem; | |
| height: 0; | |
| } | |
| 100% { | |
| width: 0; | |
| height: 0; | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes labels-inactive { | |
| to { | |
| transform: translateY(0); | |
| } | |
| } | |
| @keyframes leftLabel-active { | |
| from { | |
| transform: translateX(-100%); | |
| } | |
| } | |
| @keyframes leftLabel-inactive { | |
| to { | |
| transform: translateX(-100%); | |
| } | |
| } | |
| @keyframes rightLabel-active { | |
| from { | |
| transform: translateX(-300%); | |
| } | |
| } | |
| @keyframes rightLabel-inactive { | |
| to { | |
| transform: translateX(-300%); | |
| } | |
| } | |
| @keyframes bg-active { | |
| from { | |
| transform: translateX(-100%); | |
| } | |
| to { | |
| transform: translateX(0); | |
| } | |
| } | |
| @keyframes bg-inactive { | |
| from { | |
| transform: translateX(0); | |
| } | |
| to { | |
| transform: translateX(100%); | |
| } | |
| } | |
| @keyframes day-active { | |
| 50% { | |
| transform: scale(1.5); | |
| } | |
| 100% { | |
| transform: scale(1); | |
| } | |
| } | |
| .meta { | |
| top: 50%; | |
| transform: translateY(-50%); | |
| font-size: 1.2rem; | |
| p, a { color: rgba(255, 255, 255, 0.5); } | |
| h1 { | |
| font-size: 3rem; | |
| line-height: 1.2; | |
| font-weight: 300; | |
| color: $color-text-light; | |
| } | |
| p { line-height: 1.4; } | |
| a:hover { | |
| color: rgba(255, 255, 255, 0.7); | |
| } | |
| } | |
| .device { | |
| position: absolute; | |
| right: 2rem; | |
| height: $device-height; | |
| width: $device-width; | |
| padding: 90px 10px; | |
| border: 5px solid $color-device-border; | |
| border-radius: 60px; | |
| background-color: $color-device; | |
| box-shadow: 0 0 50px 10px rgba(0,0,0,0.1); | |
| &:before, &:after { | |
| content: ''; | |
| position: absolute; | |
| z-index: 2; | |
| } | |
| &:before { | |
| width: 20%; | |
| height: 10px; | |
| top: 40px; | |
| left: 40%; | |
| border-radius: 10px; | |
| background-color: $color-device-part; | |
| } | |
| &:after { | |
| width: 50px; | |
| height: 50px; | |
| border-radius: 50%; | |
| border: solid 5px lighten($color-device-part, 10%); | |
| left: calc(50% - 25px); | |
| bottom: 15px; | |
| } | |
| header { | |
| height: $header-height; | |
| background-color: $color-header; | |
| } | |
| section { | |
| height: calc(100% - #{$header-height}); | |
| width: 100%; | |
| overflow: hidden; | |
| background-color: $color-app; | |
| } | |
| } |