Search code examples
htmlcssstyled-components

Changing the order of elements created using ::before and ::after in CSS


I've tried to simplify my problem into the below:

.wrapper {
  position: relative;
  display: inline-flex;
  min-height: 1.5rem;
  border: 1px solid black;
  margin-right: 1rem;
  padding-right: 1.5rem;
}

.input {
  position: absolute;
  z-index: -1;
  opactiy: 0;
}

.label-wrapper {
  margin-left: 2rem;
}

.label {
  position: relative;
  margin-bottom: 0;
}

 .label:before {
    position: absolute;
    top: 4px;
    left: -24px;
    display: block;
    width: 20px;
    height: 20px;
    pointer-events: none;
    content: "";
    background-color: #fff;
  }

.label:after {
   position: absolute;
   top: 4px;
   left: -24px;
   display: block;
   height: 40px;
   content: "";
   background-repeat: no-repeat;
   background-position: center center;
   background-size: 50% 50%;
}
<div class="wrapper">
  <input class="input" type="checkbox"></input>
  <label class="label">
    <div class="label-wrapper">
      Option 1
    </div>  
  </label>
</div>

In addition to this, I have the following CSS (in a StyledComponent) that adds a "check" to the checkbox when the user clicks on the hidden input in the .input:

  &[type="checkbox"]:checked ~ label::after {
    background-image: url("${checkboxImage}");
    top: -2px;
    left: -29px;
    width: 30px;
    height: 30px;
  }

This means it behaves as a checkbox should - however, I want to swap my elements around so that the checkbox sits to the right of the text instead of the left, to do this I have tried re-ordering the input so that it comes after the label but then the hidden input (which is handling the actual click behaviour is disjointed from the CSS checkbox? Can anyone point me in the direction of how I might resolve this?

Summary: Using :before & :after to create a visual checkbox, but the logic for that checkbox is actually handled by input (which is hidden) - how can I move both the visual & hidden input to the right of the text?

Edit: enter image description here


Solution

  • Its very simple with display: flex and flex-direction: row-reverse.

    .label-wrapper {
      margin-left: 24px;
      margin-right: 0;
      flex-grow: 1; /* ADDED THIS */
    }
    
    .label {
      position: relative;
      margin-bottom: 0;
      display:flex;
      flex-direction: row;
      flex: 1; /* ADDED THIS */
    }
    .label.reverse{
      flex-direction: row-reverse;
    }
    

    See the Snippet below:

    .wrapper {
      position: relative;
      display: inline-flex;
      min-height: 1.5rem;
      border: 1px solid black;
      margin-right: 1rem;
      padding: 0.5rem;
      width: 200px;
    }
    
    .input {
      position: absolute;
      z-index: -1;
      visibility: hidden;
    }
    
    .label-wrapper {
      margin-left: 24px;
      margin-right: 0;
      flex-grow: 1;
    }
    
    .label.reverse > .label-wrapper {
      margin-left: 0;
      margin-right: 24px;
    }
    
    .label {
      position: relative;
      margin-bottom: 0;
      display:flex;
      flex-direction: row;
      flex: 1;
    }
    
    .label.reverse{
      flex-direction: row-reverse;
    }
    
     .label:before {
     position:absolute;
        display: block;
        width: 20px;
        height: 20px;
        content: "";
        background-color: #fff;
        border: 1px solid black;
        border-radius:4px;
      }
    
    .label:after {
       position: absolute;
       display: block;
       height: 20px;
       content: "";
       background-repeat: no-repeat;
       background-position: center center;
       background-size: 80%;
    }
    
    input[type="checkbox"]:checked ~ .label::after {
        background-image: url("https://cdn-icons-png.flaticon.com/512/447/447147.png");
        width: 20px;
        height: 20px;
      }
    <div class="wrapper">
      <input class="input input1" name="checkbox1" id="checkbox1" type="checkbox">
      <label class="label" for="checkbox1">
        <div class="label-wrapper">
          Option 1
        </div>  
      </label>
    </div>
    
    
    <div class="wrapper">
      <input class="input input2" name="checkbox2" id="checkbox2" type="checkbox">
      <label class="label reverse" for="checkbox2">
        <div class="label-wrapper">
          Option 2
        </div>  
      </label>
    </div>