These simple CSS blocks are alive. Each block reacts to its neighbors by transforming border-radius and color. Endless block formations, endless reactions between them.
A Pen by Yogev Ahuvia on CodePen.
These simple CSS blocks are alive. Each block reacts to its neighbors by transforming border-radius and color. Endless block formations, endless reactions between them.
A Pen by Yogev Ahuvia on CodePen.
| // Magic Number (don't go too low): | |
| var blockSize = 100; | |
| /* Reactive CSS Transitions © Yogev Ahuvia | |
| * ======================================= | |
| * These simple CSS blocks are alive. Each | |
| * block reacts to its neighbors by | |
| * transforming border-radius and color. | |
| * Endless block formations, endless | |
| * reactions between them. | |
| * --------------------------------------- | |
| * Works best on Google Chrome. | |
| */ | |
| var elements = []; | |
| var x, y, index, isEvenRow; | |
| var $container, $window; | |
| function init() { | |
| $container = $('body'); | |
| $window = $(window); | |
| x = (blockSize * 0.25); | |
| y = -(blockSize * 0.5); | |
| index = 0; | |
| isEvenRow = false; | |
| } | |
| $(document).ready(function() { | |
| init(); | |
| build(); | |
| }); | |
| $(window).resize(function() { | |
| init(); | |
| build(); | |
| onCheck(); | |
| }); | |
| function build() { | |
| do { | |
| updateRowFlag(); | |
| if (!elements[index]) { | |
| createNewBlock(x,y,index); | |
| } else { | |
| var elemObj = elements[index]; | |
| $(elemObj.input).css({'left': x+'px', 'top': y+'px'}); | |
| $(elemObj.block).css({'left': x+'px', 'top': y+'px'}); | |
| } | |
| updateCoords(); | |
| index++; | |
| } while (y <= $window.height() + blockSize); | |
| } | |
| function createNewBlock(x,y,index) { | |
| var style = ' style="width: '+blockSize+'px; height: '+blockSize+'px; left: '+x+'px; top: '+y+'px;"'; | |
| var $input = $('<input type="checkbox"'+style+'></input>'); | |
| var $block = $('<div class="block"'+style+'></div>'); | |
| $input.on('click', onCheck); | |
| elements.push({ input : $input[0], block : $block[0] }); | |
| $container.append($input, $block); | |
| } | |
| function updateRowFlag() { | |
| if (x > $window.width()) { | |
| isEvenRow = !isEvenRow; | |
| x = (isEvenRow ? -(blockSize*0.5) : (blockSize*0.25)); | |
| y += (blockSize*0.75); | |
| } | |
| } | |
| function updateCoords() { | |
| x += blockSize + (blockSize * 0.5); | |
| } | |
| function getNeighbours(index, elem) { | |
| var neighbors = { Ne: undefined, NEe: undefined, Ee: undefined, SEe: undefined, Se: undefined, SWe: undefined, We: undefined, NWe: undefined }; | |
| var Nc = { x : elem.offsetLeft + (elem.offsetWidth / 2), | |
| y : elem.offsetTop - elem.offsetHeight }; | |
| var NEc = { x : elem.offsetLeft + elem.offsetWidth, | |
| y : elem.offsetTop - (elem.offsetHeight / 2) }; | |
| var SEc = { x : elem.offsetLeft + elem.offsetWidth, | |
| y : elem.offsetTop + elem.offsetHeight }; | |
| var Sc = { x : elem.offsetLeft + (elem.offsetWidth / 2), | |
| y : elem.offsetTop + (elem.offsetHeight * 2) }; | |
| var SWc = { x : elem.offsetLeft, | |
| y : elem.offsetTop + elem.offsetHeight }; | |
| var NWc = { x : elem.offsetLeft, | |
| y : elem.offsetTop - (elem.offsetHeight / 2) }; | |
| for (var i = 0; i < elements.length; i++) { | |
| var cur = elements[i].input; | |
| if (isCoordOnElement(Nc.x, Nc.y, cur)) { | |
| neighbors.Ne = cur; | |
| } | |
| else if (isCoordOnElement(NEc.x, NEc.y, cur)) { | |
| neighbors.NEe = cur; | |
| } | |
| else if (isCoordOnElement(SEc.x, SEc.y, cur)) { | |
| neighbors.SEe = cur; | |
| } | |
| else if (isCoordOnElement(Sc.x, Sc.y, cur)) { | |
| neighbors.Se = cur; | |
| } | |
| else if (isCoordOnElement(SWc.x, SWc.y, cur)) { | |
| neighbors.SWe = cur; | |
| } | |
| else if (isCoordOnElement(NWc.x, NWc.y, cur)) { | |
| neighbors.NWe = cur; | |
| } | |
| } | |
| if (elements[index-1]) | |
| neighbors.We = elements[index-1].input; | |
| if (elements[index+1]) | |
| neighbors.Ee = elements[index+1].input; | |
| return neighbors; | |
| } | |
| function isCoordOnElement(x, y, elem) { | |
| if (x > elem.offsetLeft && | |
| x < (elem.offsetLeft + elem.offsetWidth) && | |
| y > elem.offsetTop && | |
| y < (elem.offsetTop + elem.offsetHeight)) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| function clearEffects($elem) { | |
| $elem.removeClass('Ns NWs NEs NWNEs Es SEs NESEs Ss SWs SESWs Ws NWs NWSWs NSs WEs'); | |
| } | |
| function onCheck(e) { | |
| for (var i = 0; i < elements.length; i++) { | |
| var elemObj = elements[i]; | |
| var neighbors = getNeighbours(i, elemObj.input); | |
| var $block = $(elemObj.block); | |
| clearEffects($block); | |
| if (neighbors.Ne && neighbors.Ne.checked) | |
| $block.addClass('Ns'); | |
| if (neighbors.NEe && neighbors.NEe.checked) | |
| $block.addClass('NEs'); | |
| if (neighbors.Ee && neighbors.Ee.checked) | |
| $block.addClass('Es'); | |
| if (neighbors.SEe && neighbors.SEe.checked) | |
| $block.addClass('SEs'); | |
| if (neighbors.Se && neighbors.Se.checked) | |
| $block.addClass('Ss'); | |
| if (neighbors.SWe && neighbors.SWe.checked) | |
| $block.addClass('SWs'); | |
| if (neighbors.We && neighbors.We.checked) | |
| $block.addClass('Ws'); | |
| if (neighbors.NWe && neighbors.NWe.checked) | |
| $block.addClass('NWs'); | |
| } | |
| } |
| @import "compass"; | |
| input { | |
| display: block; | |
| position: absolute; | |
| appearance: none; | |
| cursor: pointer; | |
| z-index: 1; | |
| transform-origin: 50% 50%; | |
| transform: rotate(45deg); | |
| opacity: 0; | |
| &:hover + .block { | |
| box-shadow: 1px 1px 1px 0px rgba(0,0,0,1), inset 1px 1px 1px 0px rgba(255,255,255,1); | |
| background: #ff9ea3; | |
| } | |
| &:checked + .block { | |
| background: #F9D423; | |
| border-radius: 100%; | |
| &.Ns { | |
| border-top-left-radius: 5px; | |
| } | |
| &.NEs { | |
| border-top-left-radius: 5px; | |
| border-top-right-radius: 5px; | |
| } | |
| &.Es { | |
| border-top-right-radius: 5px; | |
| } | |
| &.SEs { | |
| border-top-right-radius: 5px; | |
| border-bottom-right-radius: 5px; | |
| } | |
| &.Ss { | |
| border-bottom-right-radius: 5px; | |
| } | |
| &.SWs { | |
| border-bottom-left-radius: 5px; | |
| border-bottom-right-radius: 5px; | |
| } | |
| &.Ws { | |
| border-bottom-left-radius: 5px; | |
| } | |
| &.NWs { | |
| border-bottom-left-radius: 5px; | |
| border-top-left-radius: 5px; | |
| } | |
| } | |
| } | |
| .block { | |
| position: absolute; | |
| background: #FF4E50; | |
| border-radius: 5px; | |
| transition: border-radius 750ms, background 500ms; | |
| transform-origin: 50% 50%; | |
| transform: rotate(45deg); | |
| box-shadow: 1px 1px 1px 0px rgba(0,0,0,1), inset 1px 1px 1px 0px rgba(255,255,255,0.8); | |
| } | |
| body { | |
| background: #222; | |
| overflow: hidden; | |
| position: absolute; | |
| width: 100%; | |
| height: 100%; | |
| } |