Mobiscroll positioning

What you need

Time needed   About 15 minutes of time
Tools needed   A text editor and a browser
Knowledge needed   Basic HTML, CSS and jQuery knowledge

Mobiscroll started out as Date & Time picker simulating native UI controls (like datepicker, timepicker, spinning list etc.) of an OS, which were not possible to invoke in web apps, at least not on every platform.

For some time it supported only one display mode, a modal popup, which appeared in the center of the viewport. But native controls are positioned differently on different platforms:

Timepicker on Android 2.2

Timepicker on Android 2.2

Spinning list on iPhone

Spinning list on iPhone

Datepicker on iPad

Datepicker on iPad

So quickly the most requested feature was to be able to position Mobiscroll in different ways.
The first improvement we introduced was the ‘inline’ display mode, giving the possibility to developers to position the scroller where and how they want it (v2.0). But we wanted more. We wanted Mobiscroll to be extremely easy to use and take the burden off the poor developers.

So we decided to implement the following 3 new modes: ‘bottom’, ‘top’ and ‘bubble’. Position ‘top’ and ‘bottom’ imitates the iPhone’s behavior, while ‘bubble’ imitates the iPad’s behavior, where the picker appears in a bubble pointing at the triggering element – this is very useful on larger screens, like tablets or desktops, because you don’t have to move your hand or cursor in a different part of the screen, remaining close to the triggering touch or click.

How it’s made

In the following section I’ll explain how the positioning it’s done in a small tutorial.

The HTML

We will create a few divs and some buttons. #elm is the positioned element, #anchor is the relative element for ‘bubble’ positioning, #controls is a container for the triggering buttons.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Positioning</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <script src="http://code.jquery.com/jquery-1.9.0.min.js" type="text/javascript"></script>
    <script src="pos.js" type="text/javascript"></script>
</head>
 
<body>
    <div id="elm">
        <button id="hide">Hide</button>
    </div>
 
    <div id="controls">
        <button id="top" class="pos">Top</button>
        <button id="bottom" class="pos">Bottom</button>
        <button id="center" class="pos">Center</button>
        <button id="bubble" class="pos">Bubble</button>
    </div>
 
    <div id="anchor"></div>
</body>
</html>

The CSS

The body has a large, 2000px height, so we can test our positioning on a scrollable page.

The control container has fixed positioning aligned to left, so it is always visible, no matter where the page is currently scrolled.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
body {
    height: 2000px;
    padding: 0;
    margin: 0;
    font-family: arial, verdana, sans-serif;
    font-size: 12px;
}
 
#elm {
    position: absolute;
    z-index: 10;
    display: none;
    width: 300px;
    height: 100px;
    padding: 20px 0;
    background: #ddd;
    text-align: center;
}
 
#controls {
    position: fixed;
    top: 50%;
    left: 0;
    height: 138px;
    margin-top: -69px;
    background: #aaa;
}
 
#controls button {
    display: block;
    width: 60px;
    margin: 10px;
}
 
#anchor {
    width: 150px;
    height: 30px;
    background: #aaa;
    position: absolute;
    top: 500px;
    right: 40px;
}

Calculating the position

The positioning is done by clicking on the buttons in the controls container. The buttons have the same .pos css class, we will use that to attach the click handler. We will use the clicked button’s id, to decide where to position the element.

We also need to calculate the dimensions of the different elements (see the figures below). Note that we’re using the outerWidth and outerHeight jquery functions, which also includes the padding and borders into the dimensions.

At the end of the handler we apply the calculated values to the element using jquery’s css function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    $('.pos').click(function() {
        var top,
            left,
            width = '',
            elm = $('#elm').css({ width: '' }).show(), // Reset the width, and show the element
            anchor = $('#anchor'),
            scrollTop = $(window).scrollTop(),
            viewPortWidth = $(window).width(),
            viewPortHeight = $(window).height(),
            scrollerWidth = elm.outerWidth(),
            scrollerHeight = elm.outerHeight(),
            anchorWidth = anchor.outerWidth(),
            anchorHeight = anchor.outerHeight(),
            anchorOffsetTop = anchor.offset().top,
            anchorOffsetLeft = anchor.offset().left;
 
        switch (this.id) {
            case 'center':
                // ...
                // See calculations in the next section 
                break;
            case 'top':
                // ...
                // See calculations in the next section
                break;
            case 'bottom':
                // ...
                // See calculations in the next section 
                break;
            case 'bubble':
                // ...
                // See calculations in the next section 
                break;
        }
 
        // Apply the calculated values to the element
        elm.css({
            width: width,
            top: top,
            left: left
        });
    });

1. Centered

The element is positioned at the center of the viewport.

document
viewport
scroller
scrollTop
viewPortHeight
scrollerHeight
viewPortWidth
scrollerWidth

 

1
2
top = scrollTop + (viewPortHeight - scrollerHeight) / 2;
left = (viewPortWidth - scrollerWidth) / 2;

2. Top

The element is displayed at the top of the viewport in full width.

document
viewport
scroller
scrollTop
1
2
3
width = '100%';
top = scrollTop;
left = 0;

3. Bottom

The element is displayed at the bottom of the viewport in full width.

document
viewport
scroller
scrollTop
viewPortHeight
scrollerHeight
1
2
3
4
width = '100%';
top = scrollTop + viewPortHeight - scrollerHeight;
top = top &lt; 0 ? 0 : top // Don't go out of screen
left = 0;

4. Bubble

The element is positioned relative to an anchor element (by default the input element on which the scroller was called), with an arrow pointing at this element. Positioning decides to display  the element above or below the anchor element.

document
viewport
scroller
anchor
scrollTop
viewPortHeight
scrollerHeight
anchorHeight
viewPortWidth
scrollerWidth
anchorWidth
anchorOffsetLeft
anchorOffsetTop

 

1
2
3
4
5
6
7
8
9
10
11
top = anchorOffsetTop - scrollerHeight - 3; // above anchor element
left = anchorOffsetLeft - (scrollerWidth - anchorWidth) / 2;
 
// If there’s not enough space above the anchor element, or anchor element is out of screen, position below anchor element:
if ((top < scrollTop) || (anchorOffsetTop > scrollTop + viewPortHeight)) {
    top = anchorOffsetTop + anchorHeight + 3;
}
 
// Keep a minimum 20px margin from left and right:
left = left > (viewPortWidth - scrollerWidth - 20) ? (viewPortWidth - scrollerWidth - 20) : left;
left = left < 20 ? 20 : left;

Hiding the popup

The positioned element contains a #hide button, so we need to attach a click event handler to the button, to hide the element on button click.

1
2
3
$('#hide').click(function() {
    $('#elm').hide();
});

Summary

Download the Source Files
Play with it on jsFiddle

The actual code that is used for positioning in Mobiscroll can be found in the position function of mobiscroll.core.js

More eye-candy

On the top of that we created the animation module, to make it more awesome. Beside the slide up / slide down animations known from iOS, we also added pop and fade, and the cool 3d flip and swing effects.

Start building better products
Sign up and get posts like this in your inbox. We respect your time and will send you only the good stuff!

Tags: , , ,

  • Murali

    hi,

    I have just started mobiscroll. I was wondering how can I get mobiscroll to show once the page loads?

    And another thing is – when i scroll, is there an event that fires? And how can I use that event to update/display the current selection?

    Thanks a ton,
    Murali