1

I've come up with the following solution for the toggle switch:

.cookiemanagement__switchWrapper {
  display: flex;
  align-items: center;
}
.cookiemanagement__switchWrapper:last-of-type {
  margin-top: 15px;
}
.cookiemanagement__switch {
  display: inline-block;
  position: relative;
}
.cookiemanagement__switchInput {
  cursor: pointer;
  height: 100%;
  opacity: 0;
  position: absolute;
  width: 100%;
  z-index: 1;
}
.cookiemanagement__switchToggle {
  align-items: center;
  background-color: #9a3d37;
  border-radius: 50px;
  display: flex;
  height: 24px;
  justify-content: space-between;
  position: relative;
  transition: background-color ease-out 0.3s;
  z-index: 0;
}
.cookiemanagement__switchToggle:before {
  background: #fff;
  box-shadow: 1px 0 2px #646464;
  border-radius: 50%;
  border: 1px solid #aaaaaa;
  content: "";
  display: block;
  height: 24px;
  left: 0;
  position: absolute;
  top: 0;
  transition: 0.2s ease-out;
  width: 24px;
  z-index: 2;
}
.cookiemanagement__switchToggleValue {
  text-transform: uppercase;
  line-height: normal;
  transition: opacity 0.2s ease-out 0.1s;
}
.cookiemanagement__switchToggleValue--on {
  margin: 0 4px 0 8px;
  opacity: 0;
}
.cookiemanagement__switchToggleValue--off {
  margin: 0 8px 0 4px;
  opacity: 1;
}
.cookiemanagement__switchInput:checked ~ .cookiemanagement__switchToggle {
  background-color: #6a7d39;
}
.cookiemanagement__switchInput:checked ~ .cookiemanagement__switchToggle:before {
  left: calc(100% - 24px);
  box-shadow: -1px 0 2px #646464;
}
.cookiemanagement__switchInput:checked ~ .cookiemanagement__switchToggle .cookiemanagement__switchToggleValue--on {
  opacity: 1;
}
.cookiemanagement__switchInput:checked ~ .cookiemanagement__switchToggle .cookiemanagement__switchToggleValue--off {
  opacity: 0;
}
.cookiemanagement__switchLabel {
  margin-left: 15px;
}
<div class="cookiemanagement__switch">
    <input class="cookiemanagement__switchInput" id="id1140334900" role="switch" type="checkbox" value="3" name="analytics3">
    <div class="cookiemanagement__switchToggle">
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--on">yes</span>
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--off">no</span>
    </div>
</div>



<div class="cookiemanagement__switch">
    <input class="cookiemanagement__switchInput" id="id1140334900" role="switch" type="checkbox" value="3" name="analytics3">
    <div class="cookiemanagement__switchToggle">
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--on">diakh</span>
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--off">ara</span>
    </div>
</div>

However, I have some issues with supporting the internationalization of the values. Since right now the width of the whole element is generated from the width of two children which is "YES" and not "NO" text.

But if longer values are used like "DIAKH" and "ARA" (Georgian) the element looks very wide.

So I am investigating the way to make the whole component width to equal:
width of the biggest children (text length) + 8px + 26px

8px - margin between circle and text (red rectangle part)
26px - width/height of the circle (orange rectangle part)

Below is the illustration of what is being intended to describe, where DIAKH text represents the biggest child.

enter image description here

volna
  • 1,856
  • 4
  • 14
  • 47
  • Does this answer your question? [Is there a CSS parent selector?](https://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector) – disinfor Jan 29 '20 at 18:35
  • yes, in this case it's div with `cookiemanagement__switch` class – volna Jan 29 '20 at 18:36

3 Answers3

2

You can achieve that using flexbox on the parent of this switchs and the width: fit-content property:

ul {
  display: flex;
  flex-direction: column;
  width: fit-content;
}

.cookiemanagement__switchWrapper {
  display: flex;
  align-items: center;
  width: 100%;
}

.cookiemanagement__switchWrapper:last-of-type {
  margin-top: 15px;
}

.cookiemanagement__switch {
  display: inline-block;
  position: relative;
  width: 100%;

}

.cookiemanagement__switchInput {
  cursor: pointer;
  height: 100%;
  opacity: 0;
  position: absolute;
  width: 100%;
  z-index: 1;
}

.cookiemanagement__switchToggle {
  align-items: center;
  background-color: #9a3d37;
  border-radius: 50px;
  display: flex;
  height: 24px;
  justify-content: space-between;
  position: relative;
  transition: background-color ease-out 0.3s;
  z-index: 0;
}

.cookiemanagement__switchToggle:before {
  background: #fff;
  box-shadow: 1px 0 2px #646464;
  border-radius: 50%;
  border: 1px solid #aaaaaa;
  content: "";
  display: block;
  height: 24px;
  left: 0;
  position: absolute;
  top: 0;
  transition: 0.2s ease-out;
  width: 24px;
  z-index: 2;
}

.cookiemanagement__switchToggleValue {
  text-transform: uppercase;
  line-height: normal;
  transition: opacity 0.2s ease-out 0.1s;
}

.cookiemanagement__switchToggleValue--on {
  margin: 0 4px 0 8px;
  opacity: 0;
}

.cookiemanagement__switchToggleValue--off {
  margin: 0 8px 0 4px;
  opacity: 1;
}

.cookiemanagement__switchInput:checked~.cookiemanagement__switchToggle {
  background-color: #6a7d39;
}

.cookiemanagement__switchInput:checked~.cookiemanagement__switchToggle:before {
  left: calc(100% - 24px);
  box-shadow: -1px 0 2px #646464;
}

.cookiemanagement__switchInput:checked~.cookiemanagement__switchToggle .cookiemanagement__switchToggleValue--on {
  opacity: 1;
}

.cookiemanagement__switchInput:checked~.cookiemanagement__switchToggle .cookiemanagement__switchToggleValue--off {
  opacity: 0;
}

.cookiemanagement__switchLabel {
  margin-left: 15px;
}
<ul>
  <li class="cookiemanagement__switchWrapper">
    <div class="cookiemanagement__switch">
      <input class="cookiemanagement__switchInput" id="id1140334900" role="switch" type="checkbox" value="3" name="analytics3">
      <div class="cookiemanagement__switchToggle">
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--on">yes</span>
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--off">no</span>
      </div>
    </div>
  </li>

  <li class="cookiemanagement__switchWrapper">
    <div class="cookiemanagement__switch">
      <input class="cookiemanagement__switchInput" id="id1140334900" role="switch" type="checkbox" value="3" name="analytics3">
      <div class="cookiemanagement__switchToggle">
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--on">diakh</span>
        <span class="cookiemanagement__switchToggleValue cookiemanagement__switchToggleValue--off">ara</span>
      </div>
    </div>
  </li>
</ul>
johannchopin
  • 7,327
  • 6
  • 22
  • 62
  • I have to apologize for not properly describing the case (just added the image), but thank you for the suggestion the fit content property :-) – volna Jan 29 '20 at 18:50
  • 1
    @volna Can you tell little bit more of what you want ? Your title is **Make parent width equal to the highest of the children width** and my answer present this result. – johannchopin Jan 29 '20 at 18:57
  • Ofc, @johannchopin I would like to support different word lengths inside the switcher and avoid it resulting too wide. So I am looking for a way to limit the parent div "switcher itself" to width of the longest + 32px. I've also uploaded the image to illustrate the case :) – volna Jan 29 '20 at 19:00
  • 1
    @volna Do you mean something like this ? https://jsfiddle.net/0aexk9h2/34/ – johannchopin Feb 03 '20 at 14:10
  • thank you for the help it's almost what I am trying to achieve. I am looking for the way to "fix" the width to be always as the biggest child. If there is some space left when the other text is smaller it's acceptable. In simple words, the width shouldn't change and stay the same all the time. – volna Feb 03 '20 at 14:13
  • that's a possibility I have tried, however, what actually tricks me is how to achieve that without hardcoded width for the text values :) – volna Feb 03 '20 at 14:41
  • 1
    Can you use `javascript` ? – johannchopin Feb 03 '20 at 14:43
  • I can, but was wondering if there is CSS only approach to achieve that – volna Feb 03 '20 at 14:43
1

One of the possible solutions is using a negative margin-top to put yes and no one behind another, while keeping them both in the flow so the bigger one would give its width to the parent:

p * {
  box-sizing: border-box;
  margin: 0;
  padding: 0
}

label {
  position: relative;
  display: inline-block;
  margin: 0 0 0 .5em;
  color: #fff;
}

input {
  display: none
}

.key {
  position: absolute;
  z-index: 1;
  top: -.2em;
  left: -.05em;
  width: 2em;
  height: 2em;
  border: solid 1px rgba(0, 0, 0, .3);
  border-radius: 55%;
  box-shadow: .1em .1em .1em -.05em rgba(0, 0, 0, .5);
  background: ivory;
  transition: .3s;
}

.yes,
.no {
  display: block;
  margin: 0;
  border-radius: .8em;
  line-height: 1.6;
  box-shadow: inset .1em .1em .1em -.05em rgba(0, 0, 0, .3);
  transition: opacity .3s;
}

.yes {
  padding: 0 2.5em 0 .5em;
  background: forestgreen;
  opacity: 0;
}

.no {
  margin-top: -1.6em;
  padding: 0 .5em 0 2.5em;
  text-align: right;
  background: firebrick;
  opacity: 1;
}

:checked~.key {
  left: calc(100% - 2em);
}

:checked~.yes {
  opacity: 1
}

:checked~.no {
  opacity: 0
}
<p>English:
  <label>
    <input type="checkbox" checked>
    <span class="key"></span>
    <span class="yes">YES</span>
    <span class="no">NO</span>
  </label>
</p>

<p>Georgian:
  <label>
    <input type="checkbox">
    <span class="key"></span>
    <span class="yes">DIAKH</span>
    <span class="no">ARA</span>
  </label>
</p>

<p>Scots Gaelic:
  <label>
    <input type="checkbox" checked>
    <span class="key"></span>
    <span class="yes">THA</span>
    <span class="no">CHAN EIL</span>
  </label>
</p>
Kosh
  • 14,657
  • 2
  • 15
  • 31
  • Thank you for the suggestion, Kosh. I have moved forward with the way you suggested. But used flex with flex column on the parent div and then move on the child with `transform translateY` also does the trick :-) – volna Feb 04 '20 at 11:33
  • @volna, happy to help! – Kosh Feb 04 '20 at 14:22
1

Here is an idea with CSS grid where the trick is to make both element inside the same area. You can also keep the same HTML structure.

Relevant code:

.switchToggle {
  ...
  display: grid;
  align-items:center;
  ...
}
.switchToggle > * {
  grid-area:1/1;
}
.switchToggleValue--on {
  padding-right:32px;
}
.switchToggleValue--off {
  padding-left:32px;
  text-align:right;
}

Full code:

.switch {
  display: inline-block;
  position: relative;
  margin:5px;
}
.switchInput {
  cursor: pointer;
  height: 100%;
  opacity: 0;
  position: absolute;
  width: 100%;
  z-index: 1;
}
.switchToggle {
  background-color: #9a3d37;
  border-radius: 50px;
  display: grid;
  align-items:center;
  height: 24px;
  position: relative;
  transition: background-color ease-out 0.3s;
  z-index: 0;
}
.switchToggle > * {
  grid-area:1/1;
}
.switchToggleValue--on {
  padding-right:32px;
}
.switchToggleValue--off {
  padding-left:32px;
  text-align:right;
}
.switchToggle:before {
  content: "";
  background: #fff;
  box-shadow: 1px 0 2px #646464;
  border-radius: 50%;
  border: 1px solid #aaaaaa;
  height: 24px;
  left: 0;
  position: absolute;
  top: 0;
  transition: 0.2s ease-out;
  width: 24px;
  z-index: 2;
}
.switchToggleValue {
  text-transform: uppercase;
  line-height: normal;
  transition: opacity 0.2s ease-out 0.1s;
}
.switchToggleValue--on {
  margin: 0 4px 0 8px;
  opacity: 0;
}
.switchToggleValue--off {
  margin: 0 8px 0 4px;
  opacity: 1;
}
.switchInput:checked ~ .switchToggle {
  background-color: #6a7d39;
}
.switchInput:checked ~ .switchToggle:before {
  left: calc(100% - 24px);
  box-shadow: -1px 0 2px #646464;
}
.switchInput:checked ~ .switchToggle .switchToggleValue--on {
  opacity: 1;
}
.switchInput:checked ~ .switchToggle .switchToggleValue--off {
  opacity: 0;
}
.switchLabel {
  margin-left: 15px;
}
<div class="switch">
    <input class="switchInput" role="switch" type="checkbox" value="3" name="analytics2">
    <div class="switchToggle">
        <span class="switchToggleValue switchToggleValue--on">yes</span>
        <span class="switchToggleValue switchToggleValue--off">no</span>
    </div>
</div>
<br>
<div class="switch">
    <input class="switchInput" role="switch" type="checkbox" value="3" name="analytics2">
    <div class="switchToggle">
        <span class="switchToggleValue switchToggleValue--on">no</span>
        <span class="switchToggleValue switchToggleValue--off">yes</span>
    </div>
</div>
<br>
<div class="switch">
    <input class="switchInput" role="switch" type="checkbox" value="3" name="analytics2">
    <div class="switchToggle">
        <span class="switchToggleValue switchToggleValue--on">diakh</span>
        <span class="switchToggleValue switchToggleValue--off">ara</span>
    </div>
</div>
<br>
<div class="switch">
    <input class="switchInput" role="switch" type="checkbox" value="3" name="analytics2">
    <div class="switchToggle">
        <span class="switchToggleValue switchToggleValue--on">ara</span>
        <span class="switchToggleValue switchToggleValue--off">diakh</span>
    </div>
</div>
Temani Afif
  • 180,975
  • 14
  • 166
  • 216
  • Thank you for the suggestion @Temani you are a CSS jedi :-) I was wondering if it's possible to make it work in IE, I've updated the question with the autoprefixed copy of your code to add IE grid support but it didn't make the trick. Can you please have a look in case I am missing something :) – volna Feb 04 '20 at 10:12
  • @volna you will have no luck if you want CSS grid with IE. It won't work. By the way, you should not update the question with my solution because you will make my answer irrelevant. Simply add to your question the requirement of IE support. – Temani Afif Feb 04 '20 at 10:42
  • I did it for testing purposes since not many online code env support IE, no offense :-) – volna Feb 04 '20 at 11:10
  • But anyway thank you very much for the great idea with the usage of grid it's indeed a very nice way to solve the problem – volna Feb 04 '20 at 11:14
  • @volna there is no offense ;) but you should not add it to the question because you will change its intent and people may think that you want to make the Grid solution working on IE while you only need any kind of solution working on IE. – Temani Afif Feb 04 '20 at 11:14