Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do the right positioning of css elements?

I'm doing a slider based on noUi Slider. Was trying to achieve so to say "an elegant" solution. Since my ui handle is big I made the ui base slightly bigger with extra values in base. But those values are not allowed and handle will jump back to the allowed values. I decided to put plus and minus buttons to the place where restricted values are.

But the problem is that I can't achieve the effect that when you move the handle on to the control symbols (plus/minus) they would hide behind the handle. In my case they remain on top. And I have trouble resolving this issue.

Some help/advice would be great.

Here's my code (styles are on JSFiddle):

$(document).ready(function(){

    var sliders = document.getElementById('red'),
        input = document.getElementById('handle'),
        sliderPlus = document.getElementById('slider-amount-plus'),
        sliderMinus = document.getElementById('slider-amount-minus'),
        termCur = 500;

    noUiSlider.create(sliders, {
        start: termCur,
        step: 50,
        connect: "lower",
        range: {
            'min': 0,
            'max': 1100
        },
        pips: {
            mode: 'values',
            values: [100, 500, 1000],
            density: 4.5
        }
    });
    $('<div class="value">' + termCur + ' zł' + '</div>').appendTo($('.noUi-handle', sliders));


sliders.noUiSlider.on('change', function ( values, handle ) {
    if ( values[handle] < 100 ) {
        sliders.noUiSlider.set(100);
    } else if ( values[handle] > 1000 ) {
        sliders.noUiSlider.set(1000);
    }
});
sliders.noUiSlider.on('update', function( values ) {
    termCur = values;
    if( termCur >= 100 && termCur <= 1000 ) {
    $('.value', sliders).text(parseInt(termCur) + ' zł');}
});
sliderPlus.addEventListener('click', function(){
    if(termCur < 1000) {
        var setValue = parseInt(termCur) + 50;
        sliders.noUiSlider.set(setValue);
    }
}); 
sliderMinus.addEventListener('click', function(){
    if(termCur > 100) {
        var setValue = parseInt(termCur) - 50;
        sliders.noUiSlider.set(setValue);
    }
}); 

<div class="sliders" id="red">
        <a class="controls-symbols slider-minus" id="slider-amount-minus"><i class="fa fa-minus"></i></a>
        <a class="controls-symbols slider-plus" id="slider-amount-plus"><i class="fa fa-plus"></i></a>
    </div>

https://jsfiddle.net/o7Ly845j/

like image 347
Ilya K Avatar asked Jul 03 '15 08:07

Ilya K


People also ask

How does position work in CSS?

The CSS position property defines the position of an element in a document. This property works with the left, right, top, bottom and z-index properties to determine the final position of an element on a page. There are five values the position property can take.

How do I move a div element to the right?

If you want to move the div container, make sure the container is set as position "relative." Then adding style="float: right;" will work. If you want to only move the div within that container, then you need to use float="right" on that particular element (object) instead of positioning it with a style.


2 Answers

So, taking the last @zgood fiddle, I guessed that the problem wasn't so much z order anymore, it was because both the slider bar and the plus/minus elements were getting the events, and by the time the plus/minus events got a hold of it, the slider was already at 1100 or 0. So I changed the events around so the plus/minus got the event first and stopped it from going to the bar. I really only had to stop mousedown and most of the problems fixed itself. After that, I could take out all the > 100 and < 1000 checks, because the bar behaved itself.

I also noticed that the slider button covered up the plus/minus once you got to 50/1050. So I changed the plus/minus to z-index:13 instead of 3 in the fiddle. I'm not sure which is better, so try 3 and 13 and make your own decision.

https://jsfiddle.net/guyschalnat/radpjf47/2/

$(document).ready(function(){

    var sliders = document.getElementById('red'),
        input = document.getElementById('handle'),
        termCur = 500;

    noUiSlider.create(sliders, {
        start: termCur,
        step: 50,
        connect: "lower",
        range: {
            'min': 0,
            'max': 1100
        },
        pips: {
            mode: 'values',
            values: [100, 500, 1000],
            density: 4.5
        }
    });
    $('<div class="value">' + termCur + ' zł' + '</div>').appendTo($('.noUi-handle', sliders));

    var c = $('#red > span').clone(true);
    $('#red > span').remove();
    $('.noUi-base').prepend(c);

    sliders.noUiSlider.on('update', function( values ) {
        var val = parseInt(values);
        termCur = val;
        $('.value', sliders).text(termCur + ' zł');
    });
    $('#slider-amount-plus').click(function(e){
        if(termCur < 1100) {
            termCur = termCur + 50;
            sliders.noUiSlider.set(termCur);
            $('.value', sliders).text(termCur + ' zł');
        }
       e.stopPropagation();
    }).mousedown(function(e){
       e.stopPropagation();
    });     
    $('#slider-amount-minus').click(function(e){ 
        if(termCur > 0) {
            termCur = termCur - 50;
            sliders.noUiSlider.set(termCur);
            $('.value', sliders).text(termCur + ' zł');
        }
    }).mousedown(function(e){
       e.stopPropagation();
    }); 

});
like image 66
Guy Schalnat Avatar answered Oct 09 '22 01:10

Guy Schalnat


Groups of elements with a common parent that move forward or backward together in the stacking order make up what is known as a stacking context. A full understanding of stacking contexts is key to really grasping how z-index and the stacking order work.

Every stacking context has a single HTML element as its root element. When a new stacking context is formed on an element, that stacking context confines all of its child elements to a particular place in the stacking order. That means that if an element is contained in a stacking context at the bottom of the stacking order, there is no way to get it to appear in front of another element in a different stacking context that is higher in the stacking order, even with a z-index of a billion!

New stacking contexts can be formed on an element in one of these ways:

  • When an element is the root element of a document (the element)

  • When an element has a position value other than static and a z-index value other than auto

  • When an element has an opacity value less than 1

  • In addition to opacity, several CSS properties also create stacking contexts. These include: transforms, filters, css-regions, paged media, and possibly others.


Here are the basic rules to determine stacking order within a single stacking context (from back to front):

  • The stacking context’s root element

  • Positioned elements (and their children) with negative z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)

  • Non-positioned elements (ordered by appearance in the HTML)

  • Positioned elements (and their children) with a z-index value of auto (ordered by appearance in the HTML)

  • Positioned elements (and their children) with positive z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)

Note: positioned elements with negative z-indexes are ordered first within a stacking context, which means they appear behind all other elements. Because of this, it becomes possible for an element to appear behind its own parent, which is normally not possible. This will only work if the element’s parent is in the same stacking context and is not the root element of that stacking context.


I created a "hackish" way to do this with jQuery, you can view the Fiddle here. This isn't a permanent solution though, I'm working on abstracting the positioning as it's using static values. I will also figure out why the CSS won't behave and post that here.

     $(document).mousemove(function (e) {
         var newpos = $(".noUi-handle").offset().left;

         if (newpos < 0) {
             $(".slider-minus").hide();
         } else { 
             $(".slider-minus").show();
         }

         if (newpos > 830) {
             $(".slider-plus").hide();  
         } else {  
             $(".slider-plus").show();
         }     
    });

update Here is a better version, now working on why the CSS won't do it for you.

like image 26
Tech Savant Avatar answered Oct 09 '22 00:10

Tech Savant