How to conform top glare to all child elements

Viewed 35

Goal

Make the glare layer on all visible children like a clip-path

––––––––––––

Heads Up

Child elements can be any shape with any animation
Child elements can be any svg shape with any kind of animation attached to it
So glare must be automatically dynamic and conforming

––––––––––––

What I've Done

I create an apple TV effect…
But the glare only works as a box on top of other boxes.
The glare does not conform to other shapes
Example Below

––––––––––––

What I Can't Use

Canvas - No Canvas Please - I'm not familiar with it
Clip-Path - Because child elements can be anything overflowing outside of the glare

––––––––––––

What I'm looking for

Some kind of magical CSS line of code that makes the glare layer conform to all elements under it… like a normal glare would work.
Is this possible?
Is there some way Javascript can glare it automatically?
Is there some kind of mix-blend-mode I can use to make the glare just work?
Or is this something that is just impossible?
Glare should not look like a box

––––––––––––

What I tried

I tried to scale the glare layer to scale(1.1) and use some mix-blend-mode
But I couldn't figure out how to make it work.

appleTV();

function appleTV(){
    appleTVComponents = 0;
    function rotateX(n) {return ' rotateX('+n+'deg)'}
    function rotateY(n) {return ' rotateY('+n+'deg)'}
    function translateX(n) {return ' translateX('+n+'px)'}
    function translateY(n) {return ' translateY('+n+'px)'}
    function perspective(n) {return 'perspective('+n+'px)'}
    function scale(n) {return ' scale3d('+n+','+n+','+n+')'}
    function section(s='',e) {e=document.createElement('section');e.className='appletv_'+s;return e;}
    function getWidth(e) {return e.clientWidth || e.offsetWidth || e.scrollWidth}
    function setPerspective(e) {e.style.transform = perspective(getWidth(e)*3);}
    function preventScroll(state) {if(supportsTouch){win.preventScroll=state||false;}}
    function preventDefault(e) {if (supportsTouch&&win.preventScroll){e.preventDefault();}}
    function isTouchScreen() {return 'ontouchstart' in window || navigator.msMaxTouchPoints}
    function child(e) {return e.firstChild;}
    function children(e) {return [...e.children]}
    let body = document.body,
        win = window,
        imgs = document.querySelectorAll('.appletv'),
        totalImgs = imgs.length,
        supportsTouch = isTouchScreen(),
    move = 'mousemove',
    start = 'mouseenter',
    end = 'mouseleave';
    if(supportsTouch){move='touchmove'; start='touchstart'; end='touchend';}
    if(totalImgs <= 0){return;}
    for(var l=0;l<totalImgs;l++){
        var thisImg = imgs[l],
            layerElems = [...thisImg.querySelectorAll('.appletv_layer')];
        if(!layerElems.length){continue;}
        while(thisImg.firstChild) {thisImg.removeChild(thisImg.firstChild);}
        var containerHTML = section(''),
            shineHTML = section('gloss'),
            shadowHTML = section('shadow'),
            layersHTML = section('layer'),
            layers = [];
            thisImg.id = 'appletv_'+(++appleTVComponents);
        layerElems.forEach((e,i)=>{
        let layer_ = section('rendered_layer')
            layer = section(''),
            img = e.getAttribute('data-img');
            layer_.setAttribute('data-layer',i);
            [...e.children].forEach(c=>{layer.appendChild(c)})
            if (img) {layer.style.backgroundImage = 'url('+img+')';}
            layer_.appendChild(layer);
            layersHTML.appendChild(layer_);
            layers.push(layer);
        });
        [shadowHTML,layersHTML,shineHTML].forEach(e=>{containerHTML.appendChild(e)});
        thisImg.appendChild(containerHTML);
        var w = getWidth(thisImg);
        setPerspective(thisImg)
        preventScroll();
        (function enableMovements(_thisImg,_layers,_totalLayers,_shine) {
            thisImg.addEventListener(move, e=>{processMovement(e,supportsTouch,_thisImg,_layers,_totalLayers,_shine);});
            thisImg.addEventListener(start, e=>{processEnter(_thisImg);});
            thisImg.addEventListener(end, e=>{processExit(_thisImg,_layers,_totalLayers,_shine);});
        })(thisImg,layers,layerElems.length,shineHTML);  
    };

    function processMovement(e, touchEnabled, elem, layers, totalLayers, shine){
        preventDefault(e)
        let bdst = body.scrollTop,
            bdsl = body.scrollLeft,
            pageX = (touchEnabled)? e.touches[0].pageX : e.pageX,
            pageY = (touchEnabled)? e.touches[0].pageY : e.pageY,
            offsets = elem.getBoundingClientRect(),
            w = elem.clientWidth || elem.offsetWidth || elem.scrollWidth, // width
            h = elem.clientHeight || elem.offsetHeight || elem.scrollHeight, // height
            wMultiple = 320/w,
            offsetX = 0.52 - (pageX - offsets.left - bdsl)/w, //cursor position X
            offsetY = 0.52 - (pageY - offsets.top - bdst)/h, //cursor position Y
            dy = (pageY - offsets.top - bdst) - h / 2, //@h/2 = center of container
            dx = (pageX - offsets.left - bdsl) - w / 2, //@w/2 = center of container
            yRotate = (offsetX - dx)*(0.07 * wMultiple), //rotation for container Y
            xRotate = (dy - offsetY)*(0.1 * wMultiple), //rotation for container X
            imgCSS = rotateX(xRotate)+rotateY(yRotate), //img transform
            arad = Math.atan2(dy, dx), //angle between cursor and center of container in RAD
            angle = arad * 180 / Math.PI - 90; //convert rad in degrees
        if (angle < 0) {angle = angle + 360;}
        
        if(elem.firstChild.className.indexOf(' over') != -1){imgCSS += scale(1.07);}
        elem.firstChild.style.transform = imgCSS;
        
        shine.style.background = 'linear-gradient(' + angle + 'deg, rgba(255,255,255,' + (pageY - offsets.top - bdst)/h * 0.4 + ') 0%,rgba(255,255,255,0) 80%)';
        shine.style.transform = translateX((offsetX * totalLayers) - 0.1)+translateY((offsetY * totalLayers) - 0.1);    

        var revNum = totalLayers;
        for(var ly=0;ly<totalLayers;ly++){
            layers[ly].style.transform = translateX((offsetX * revNum) * ((ly * 2.5) / wMultiple))+translateX((offsetY * totalLayers) * ((ly * 2.5) / wMultiple));
            revNum--;
        }
    }

    function processEnter(e){preventScroll(true);setPerspective(e);child(e)&&child(e).classList.add('over');}
    function processExit(elem, layers, totalLayers, shine){preventScroll();
        child(elem).classList.remove('over')
        child(elem).style.transform = '';
        shine.style = '';
        layers.forEach(e=>{e.style.transform = ''})
    }
}
body,
html {
    height: 100%;
    min-height: 100%;
  
}

body {background: linear-gradient(to bottom, #f6f7fc 0%, #d5e1e8 40%);}








.center{
  position: absolute;
  left: 50%;
  margin: 10px auto;
  transform: translateX(-50%);
}

.appletv {
position: relative !important;
margin: 0 auto !important;
    display: inline-block;
  width: 300px;
    height: 150px;
    border-radius: 5px; 
    transform-style: preserve-3d;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    cursor: pointer;
    backface-visibility: hidden;
}
.appletv.depressed {
    margin-top: 25px;
    box-shadow: 0 5px 30px rgba(0, 0, 0, 0.4);
}
.appletv_ {
    position: relative;
    width: 100%;
    height: 100%;
    border-radius: 5px;
    transition: all 0.2s ease-out;
    background: teal;
}

.appletv_container.over {z-index: 1;}

.appletv_container.over .appletv_shadow {box-shadow: 0 45px 100px rgba(14, 21, 47, 0.4), 0 16px 40px rgba(14, 21, 47, 0.4);}

.appletv_layer {
    position: relative;
    width: 100%;
    height: 100%;
    border-radius: 5px;
    /*overflow: hidden;*/
    transform-style: preserve-3d;
}


.appletv_rendered_layer {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    overflow: hidden;
    border-radius: 5px;
    transition: all 0.1s ease-out;
    transform-style: preserve-3d;
}
.appletv_rendered_layer > :first-child {
    position: absolute;
    width: 104%;
    height: 104%;
    top: -2%;
    left: -2%;
    background-repeat: no-repeat;
    background-position: center;
    background-color: transparent;
    background-size: cover;
    transition: all 0.1s ease-out;
}

.appletv_shadow {
    position: absolute;
    top: 5%;
    left: 5%;
    width: 90%;
    height: 90%;
    transition: all 0.2s ease-out;
    box-shadow: 0 8px 30px rgba(14, 21, 47, 0.6);
}

.appletv_gloss {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: 5px;
    /*display: none !important;*/
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0) 40%);
}




[data-layer="1"] {overflow: visible !important;}

[data-layer="1"] > section > section {
    position: absolute;
    background: rgb(50, 141, 210);
    width: 60px;
    height: 60px;
    border-radius: 10px;
}
[data-layer="1"] > section > section:first-child {
    left: -30px;
    top: -10px;
}

[data-layer="1"] > section > section:last-child {
    right: -20px;
    top: 50px;
}

@keyframes rotate {
    0% {transform: rotate(0);}
    100% {transform: rotate(359deg);}
}



.appletv_gloss {
    /*display: none;*/
    background-blend-mode: multiply;
}

.appletv [data-layer="1"] {
    transform: scale(0.5);
    transition: .3s ease-in-out 0s;
}
.appletv:hover [data-layer="1"] {
    transform: scale(1);
}

.appletv:hover [data-layer="1"] > section > section {
    animation: rotate 10s linear 0s infinite;
}
.appletv:hover [data-layer="1"] > section > section:last-child {
    animation: rotate 25s linear 0s infinite;
}

#hover {
  font-size: 30px;
  position: absolute;
  top: 37%;
  text-align: center;
  width: 100%;
  color: white;
  text-shadow: 0 2px 2px rgba(0,0,0,0.3) ;
}
<html>
<body>
  <section class="center">
    <section class="appletv">
      <section class="appletv appletv_layer" data-img="https://source.unsplash.com/random">
          <section id="hover">Hover Corners</section>
      </section>
      <section class="appletv appletv_layer">
          <section></section>
          <section></section>
      </section>
    </section>
  </section>
</body>
</html>

0 Answers
Related