Search code examples
htmlcssfrontendtransformtransition

How to make the parent element (span) transform over the child element (input) in CSS?


I want to make a cool effect for an input box. I want this to happen:

When the user clicks the input box, the top of the input border (border-top) to move elegantly into input border's bottom place (border-bottom).

However, I quickly learned that you can't move an elements border-top into the border-bottom's place.

So I have made a solution that works (kinda)! By placing the input inside of a span element, I'm able to transtion the span's border-top down to give the illusion that the top of the input border is moving down. The only problem is that when span's border moves over the input box, you can no longer see it since the input box has a greater z-index (I'm guessing).

Here's my solution:


<!DOCTYPE html>
<html>
<head>
<style>

/* input box - no border, no ouline, and a transition to move up (to cancel out the transtion made by the parent).*/
input{
    border: 1px solid transparent;
    outline: none;
    transition: transform 2s;
 }

/* span - red border and a transition to move down */
span{
    display: inline-block;
    content: '';
    border-top: 1px solid red;
    transition: transform 2s;
}

/* on focus of the child element of span - transform span down */

span:focus-within{
transform: translate(0%, 30px);
}

/* while active or focused on input - transform input up*/
input:active, input:focus {
transform: translate(0%, -30px);

}


</style>
</head>
<body>

<span>

<input type='text' placeholder='john doe'/>

</span>


</body>
</html>

So, naturally, I thought the solution would be to grant a higher z-index to span element. The issue is, if I do that then the whole thing breaks because input is a child of span... So, if span has a higher index, then I can never enter any text into the input box.

As shown below:


<!DOCTYPE html>
<html>
<head>
<style>

/* input box - no border, no ouline, and a transition to move up (to cancel out the transtion made by the parent).*/
input{
    border: 1px solid transparent;
    outline: none;
    transition: transform 2s;
    position: relative;
      z-index: -1;


}

/* span - red border and a transition to move down */
span{
    display: inline-block;
    content: '';
    border-top: 1px solid red;
    transition: transform 2s;
    position: relative;
    z-index: 1;

}

/* on focus of the child element of span - transform span down */

span:focus-within{
transform: translate(0%, 30px);
}

/* while active or focused on input - transform input up*/
input:active, input:focus {
transform: translate(0%, -30px);

}


</style>
</head>
<body>

<span>

<input type='text' placeholder='john doe'/>

</span>


</body>
</html>

Please may someone show me how to be able to interact with the input box and let the span border glide, visibly, across the input box?


Solution

  • Instead of trying to switch the position of two items, you can just render a line using :before. This prevents the position of the red line from altering the position of the input.

    <!DOCTYPE html>
    <html>
    <head>
    <style>
    
    /* input box - no border, no outline */
    input{
        border: 1px solid transparent;
        outline: none;
     }
    
    span{
        position: relative
    }
    
    /* red border and a transition to move up */
    span:before{
        height: 0;
        position: absolute;
        width: 100%;
        display: block;
        content: ' ';
        border-top: 1px solid red;
        transition: top 1s;
        top: 0;
    }
    
    /* on focus of the span - transform line down */
    span:focus-within:before{
        transition: top 1s;
        top: 100%;
    }
    
    </style>
    </head>
    <body>
    
    <span>
    
    <input type='text' placeholder='john doe'/>
    
    </span>
    
    
    </body>
    </html>