Home > Blockchain >  How do I make the transform: translateX value flexible according to its parent container's widt
How do I make the transform: translateX value flexible according to its parent container's widt

Time:12-05

I've done an example to demonstrate what I expect:

I have a toggle. The toggle's width may vary depending on its parent container.

And I want to use transform to control the position of the toggle-thumb, because this would result in an animation effect.

In this demo, everything works fine when the parent container has a width of 50px.

However, if you click the "ToggleWidth" button to make the toggle's parent container into a 100px width element. The transform looks bad.

I tried something like this:

transform:translate(calc(100% - x), -50%);

But the position of the thumb is still not working properly.

Is there any way I can fix it with pure CSS?

$('#dark-switch').click(()=>{

  $('#dark-toggle-thumb').toggleClass('isOn');
});


$('#toggleWidth').click(()=>{
  $('#dark-switch').toggleClass('dark-switch-vary');
})
body {padding:2em}
.dark-switch-vary {
  max-width:100px !important; 
}
#dark-switch {
  position:relative;
  width:90%;
  max-width:50px;
}

#dark-toggle-back {
  width: calc(100% - 9px);
  background: #666;
  height: 24px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  border-radius: 99px;
}
#dark-toggle-thumb {
  background: #ccc;
  height: 17px;
  border-radius: 99px;
  width: 17px;
  top: 50%;
  transform: translate(6px, -50%);
  position: absolute;
  transition: .2s;
}
#dark-toggle-thumb svg {
  width: 15px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.isOn {
   transform: translate(26px, -50%) !important;
   /* How do I make the translateX value flexible rather than a fixed number? */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="dark-switch">
  <section id="dark-toggle-back"></section>
  <section id="dark-toggle-thumb">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 3a7 7 0 0 0 7 9h2a9 9 0 1 1-9-9Z"></path></svg>
  </section>
</div>
<br><br><br><br><br>
<button id="toggleWidth">ToggleWidth</button>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Because of the way CSS works, you can't change predefined numbers. I would suggest using pure jQuery to help with doing switches (aka using $('#dark-toggle-thumb').css("translate: " number of pixels you want "px, -50%;");. Since you wanted CSS though, you would have to create a different class and add that class to your toggler, and then you could define a new class attribute in your CSS, which you can see at the bottom of the css with:

.dark-switch-long.isOn {
  transform: translate(75px, -50%) !important;
}

Then if you were to add the class dark-switch-long to your dark-toggle-thumb element, then you would be able to extend the length to the specified pixels. However, I would suggest using my first example of jQuery CSS.

EDIT: As per OP's comment, they want the width to change dynamically. CSS will make this more challenging than using jQuery, so I created a function moveThumb() that will slide the thumb to the right based on the width of the slider behind it. That function would look something like:

function moveThumb() {
  let jumpLength = $('#dark-switch').outerWidth() - 25;
  $('#dark-toggle-thumb').css("transform",  "translate("   jumpLength   "px, -50%)");
}

jumpLength calculates the total distance that #dark-toggle-thumb will have to move. Then, using jQuery CSS functionality, we can move that amount of pixels over. I updated the code snippet to show how this would work. This also includes adding a call to moveThumb() when you use the ToggleWidth button. Note that I used jQuery's hasClass function to check when I should use moveThumb.

function moveThumb() {
  let jumpLength = $('#dark-switch').outerWidth() - 25;
  $('#dark-toggle-thumb').css("transform",  "translate("   jumpLength   "px, -50%)");
}

$('#dark-switch').click(()=>{

  $('#dark-toggle-thumb').toggleClass('isOn');
  
  if ($('#dark-toggle-thumb').hasClass('isOn'))
      moveThumb();
  else
    $('#dark-toggle-thumb').css("transform", "translate(6px, -50%)");
});


$('#toggleWidth').click(()=>{
  $('#dark-switch').toggleClass('dark-switch-vary');
  if ($('#dark-toggle-thumb').hasClass('isOn'))
      moveThumb();
})
body {padding:2em}
.dark-switch-vary {
  max-width:100px !important; 
}
#dark-switch {
  position:relative;
  width:90%;
  max-width:50px;
}

#dark-toggle-back {
  width: calc(100% - 9px);
  background: #666;
  height: 24px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  border-radius: 99px;
}
#dark-toggle-thumb {
  background: #ccc;
  height: 17px;
  border-radius: 99px;
  width: 17px;
  top: 50%;
  transform: translate(6px, -50%);
  position: absolute;
  transition: .2s;
}
#dark-toggle-thumb svg {
  width: 15px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
/* TAKING OUT FOR jQuery EXAMPLE
.isOn {
   transform: translate(26px, -50%) !important;
   How do I make the translateX value flexible rather than a fixed number?
}
.dark-switch-long.isOn {
   transform: translate(75px, -50%) !important;
}
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="dark-switch">
  <section id="dark-toggle-back"></section>
  <section id="dark-toggle-thumb">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 3a7 7 0 0 0 7 9h2a9 9 0 1 1-9-9Z"></path></svg>
  </section>
</div>
<br><br><br><br><br>
<button id="toggleWidth">ToggleWidth</button>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

The main problem – you can't translate (animated) between left:0 (right:inherit/auto) and right:0 (left:inherit/auto).

However you can fix this issue by appling a calc() left offset.
I also recommend to prefer relative units like em.

$('#dark-switch').click(() => {
  $('.dark-toggle-thumb').toggleClass('isOn');
});


$('#toggleWidth').click(() => {
  $('#dark-switch').toggleClass('dark-switch-vary');
})

let fontSize = document.querySelector('#fontSize');
let darkSwitch = document.querySelector('#dark-switch');
fontSize.addEventListener('change', function(e){
  let size = e.target.value;
  darkSwitch.setAttribute('style', 'font-size:'  17*size  'px');
});
*{
box-sizing:border-box
}

body {
  padding: 2em
}

:root{
--switchH: 17px;
--switchPadding: 0.2em;
}

.dark-switch {
  position: relative;
  width: 90%;
  max-width: 3em;
  font-size: var(--switchH);
  line-height:1em;
}

.dark-toggle-back {
  width: 100%;
  background: #666;
  height: calc(1em   var(--switchPadding) *2 ) ;
  position: relative;
  border-radius: 1em;
}

.dark-toggle-thumb {
  background: #ccc;
  height: 1em;
  width: 1em;
  border-radius:100%;
  position: absolute;
  transition: 0.2s;
  left:0;
  margin: var(--switchPadding);
  right: inherit;
}


.dark-toggle-thumb svg {
  width: 1em;
  height: 1em;
  display:inline-block;
}

.dark-switch-vary {
  max-width: 50vw;
}

.isOn {
left: calc(100% - calc(1em   var(--switchPadding) *2 ) );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="dark-switch" class="dark-switch">
  <div class="dark-toggle-back">
    <span class="dark-toggle-thumb">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 3a7 7 0 0 0 7 9h2a9 9 0 1 1-9-9Z"></path></svg>
  </span>
  </div>
</div>
<br><br><br><br><br>
<button id="toggleWidth">ToggleWidth</button>
<h3>Font size</h3>
<p>
<input id="fontSize" type="range" min="1" max="5" step="0.5" value="0" />
</p>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Jquery will only handle the css class toggling.

  • Related