Create segmented controls with animations

I have a fairly simple segmented switch setting, similar to a controller. When a radio button is selected, this button gets the background color for it.

How to get background color for animating selected radio button in css?

Like this:

enter image description here

Jsfiddle

input { display: none; } input:checked + .label { background-color: yellowGreen; } 
 <label> <input type="radio" name="radioBtn" checked><span class="label">First Option</span> </label> <label> <input type="radio" name="radioBtn"><span class="label">Second Opetion</span> </label> <label> <input type="radio" name="radioBtn"><span class="label">Third Option</span> </label> 

Update

Due to lack of response, I am now open to JavaScript / JQuery. Although, if you have a clean css solution, submit it.

+8
javascript jquery html css css-animations
source share
5 answers

Ok, pure CSS, it seems I came back late, but better than not coming back, JS Fiddle -Updated (1) (2)

Updated code: added z-index value to div#radios (3) container

 body { background: #EEE url('//www.dailyfreepsd.com/wp-content/uploads/2013/09/underwater-blurred-background.jpg'); background-size: cover; } #radios { position: relative; background-color: tomato; z-index: 5; width: 363px; } input { display: none; } #bckgrnd, .labels { width: 120px; height: 30px; text-align: center; display: inline-block; padding-top: 10px; margin-right: -3px; z-index: 2; cursor: pointer; outline: 1px solid green; } #bckgrnd { background-color: orange; position: absolute; left: 0; top: 0; z-index: -1; } #rad1:checked ~ #bckgrnd { transform: translateX(0); transition: transform 0.5s ease-in-out; } #rad2:checked ~ #bckgrnd { transform: translateX(120px); transition: transform 0.5s ease-in-out; } #rad3:checked ~ #bckgrnd { transform: translateX(241px); transition: transform 0.5s ease-in-out; } 
 <div id="radios"> <input id="rad1" type="radio" name="radioBtn" checked> <label class="labels" for="rad1">First Option</label> <input id="rad2" type="radio" name="radioBtn"> <label class="labels" for="rad2">Second Option</label> <input id="rad3" type="radio" name="radioBtn"> <label class="labels" for="rad3">Third Option</label> <div id="bckgrnd"></div> </div> 

Edit:

(1) For smaller screens, you can make a media query with a specific break point if these radio stations are shown below vertically, and use translateX() instead of translateY() .

(2) my solution below adds div <div id="bckgrnd"></div> as the last child of the #radios div container, instead you can add javascript / jquery to do this, you can add this jquery: JS Fiddle 2 -Updated

 $(document).ready(function(){ $('#radios').append('<div id="bckgrnd"></div>'); }); 

(3) The value of z-index:; was added simply to ensure that #bckgrnd , whose z-index:-1 does not disappear behind the body , or some element contains #radios cases. so now we can set the background image to the body and background color for the div container without worrying about it. JS Fiddle Test

+3
source share

You'll probably need some tweaking to look right and so forth, but the general idea is here:

  input { display: none; } #rdb1:checked ~ #back { left:0 !important; } #rdb2:checked ~ #back{ left:15vw !important; } #rdb3:checked ~ #back{ left:30vw !important; } label{ width:15vw; float:left; } #back{ background-color: yellowGreen; left:0; position:fixed; width:15vw; height:12pt; z-index:-1; transition:left 500ms } 
 <div> <input type="radio" name="radioBtn" id="rdb1" checked> <label for="rdb1">First Option</label> <input type="radio" name="radioBtn" id='rdb2'> <label for="rdb2">Second Opetion</label> <input type="radio" name="radioBtn" id='rdb3'> <label for="rdb3">Third Option</label> <div id="back"></div> </div> 

The built-in snippet function makes it more buggy than it actually is, better in the fiddle: http://jsfiddle.net/Lybmk9hd/1/

+1
source share

There is something here.

 label{ position: relative; height:100%; display: block; height: 50px; } [type="radio"]{ display: none; z-index: 5; position: relative; } [type="radio"] ~ span{ transition: background .3s; height: 100%; display: -webkit-flex; display: flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; padding: 0 25px; z-index: 5; position: relative; } .bg{ position: absolute; width: 100%; height: 100%; background: #7df5a7; top: 0; z-index: 0; left: 0; width: 0; transition: .3s width; } label:nth-child(1) .bg{ right: 0; left: auto; } label:nth-child(2) .bg{ left: 0; } [type="radio"]:checked + .bg{ width: 100%; } .wrap{ border:1px solid #ddd; display: inline-flex; overflow:hidden; border-radius: 50px; } 
 <div class="wrap"> <label> <input type="radio" name="radioBtn" checked> <div class="bg"></div> <span class="label">First Option</span> </label> <label> <input type="radio" name="radioBtn"> <div class="bg"></div> <span class="label">Second Option</span> </label> </div> 
0
source share

 [l1, l2, l3].forEach(function(x){ x.onclick = function() { var r = x.getBoundingClientRect(); bg.style.left = r.left - 12 + "px"; bg.style.top = r.top - 10 + "px"; bg.style.width = r.width + 8 + "px"; bg.style.height = r.height + 4 + "px"; }; }); l1.onclick(); 
 #container { position: relative; } input[type="radio"] { display: none; } input[type="radio"]+label { display: inline-block; } #bg { background-color: #0F0; position: absolute; transition: all 0.25s ease-in-out; border-radius: 1000px; z-index: -1; } 
 <div id="container"> <div id="bg"></div> <input type="radio" id="opt1" name="grp1"><label id="l1" for="opt1">Option1</label> <input type="radio" id="opt2" name="grp1"><label id="l2" for="opt2">Option2</label> <input type="radio" id="opt3" name="grp1"><label id="l3" for="opt3">Option3 with a very long text</label> </div> 
0
source share

Here is the version using jQuery. This is a bit more complicated than the other answers, but most of the complexity is related to how I made the animation. When the backlight changes, it stretches to a new place and then shrinks to fit. This is not what your layout does, but IMHO is a smoother effect.

It's hard to explain, but it's a JSFiddle, which shows what I mean.

http://jsfiddle.net/mcgraphix/4qe8uz06/9/

The HTML is pretty much like yours, except for the added highlight:

 <div> <label> <input type="radio" name="radioBtn" ><span class="label">First Option</span> </label> <label> <input type="radio" name="radioBtn" checked><span class="label">Second Option</span> </label> <label> <input type="radio" name="radioBtn"><span class="label">Third Option with a long label</span> </label> <span class="highlight"></span> </div> 

JS:

 $(document).ready(function() { //handle to the highlight span var hl = $('.highlight'); var initialLabel = $('input[name="radioBtn"]:checked').parent(); //highlight the correct one initially in case it isn't the first one hl.css('width', initialLabel.css('width')); hl.css('left', ( initialLabel.offset().left - $("label").first().offset().left) + 'px'); //add listeners $("label").mouseup(function(event) { //figure out what we clicked on var selectedItem = $(this); //figure out where the left edge of it is var newLeft = (selectedItem.offset().left - $("label").first().offset().left); //how much do we need to change the left coordinate var changeAmount = Math.abs(parseInt(hl.css('left')) - newLeft); //figure out which direction we're going var direction = (parseInt(hl.css('left')) > newLeft) ? 'left' : 'right'; //remove all the classes to start hl.removeClass('grow-left').removeClass('grow-right').removeClass('shrink'); //set up the new CSS var newCss; if (direction === 'right') { //we're growing to the right newCss = { width: selectedItem.width() + selectedItem.offset().left - hl.offset().left + 'px' }; hl.addClass('grow-right'); } else { //we're growing to the left newCss = { width: hl.width() + changeAmount + 'px', left: newLeft + 'px' }; hl.addClass('grow-left'); } //set the initial change hl.css(newCss); //wait for it to be done, then finish the change hl.on('transitionend webkitTransitionEnd oTransitionEnd', function () { if (direction === 'right') { //we need to shrink to the right newCss = {width: selectedItem.css('width'), left: newLeft + "px"}; } else { //we need to shrink to the left newCss = {width: selectedItem.css('width')} } //apply the right transition class hl.removeClass('grow-left').removeClass('grow-right').addClass('shrink'); //apply the styles hl.css(newCss); //you could add a transitionend event listener to clean up the classes here }); }); }); 

The most important CSS styles are those that apply the transition with the correct attenuation and delay values:

 span.highlight.grow-left { transition: left 0.2s ease-in-out, width 0.2s ease-in-out; } span.highlight.grow-right { transition: width 0.2s ease-in-out, left 0.2s ease-in-out 0.2s; } span.highlight.shrink { transition: width 0.2s ease-in-out, left 0.2s ease-in-out; } 

The bottom line is that there is a "highlight" behind the labels. When you click one, it calculates the position of what you clicked, and adding classes for the right animation at the right time, you get the right animated "morphing"

0
source share

All Articles