I have a toolbar at the bottom of my mobile webapp. I'd like to be able to drag this toolbar up and down, revealing content underneath it. I'd like to be able to do this simply by using HTML/CSS, and not having to use touch/scroll events or mobile touch/scroll libraries.
I am trying to do this by overlaying a scrolling element on top of the main webapp with the toolbar and its content at the bottom. I've given this element a lower z-index than the main content so that it doesn't block the user from interacting with the main content, and given the toolbar and its content a higher z-index so that it can be seen and pulled/scrolled up.
I have created a jsFiddle that has the correct behaviour in both desktop and Android versions of Chrome. I can drag up the toolbar with my finger or by scrolling with my cursor on top of it:
Unfortunately, the toolbar does not appear in the Android browser (tested on 4.1 and 4.2).
However when I press where the toolbar should be and drag up, it doesn't scroll the page until I have moved my finger far enough to have scrolled the toolbar all the way up, if it were visible. This is how scrolling the toolbar works in Chrome, and indicates that the toolbar is scrolling properly in the Android browser. It just isn't visible.
<div id="main-content"></div>
<div id="scroller">
<div id="wrapper">
<div id="toolbar-and-content">
<div id="toolbar">Toolbar</div>
<div id="toolbar-content">Toolbar content</div>
</div>
</div>
</div>
#main-content {
position:relative;
width:100%;
height:300px;
background-color:green;
z-index:1;
}
#scroller {
position:absolute;
top:0;
width:100%;
height:300px;
overflow:auto;
}
#wrapper {
position:relative;
width:100%;
height:500px;
}
#toolbar-and-content {
position:absolute;
bottom:0;
width:100%;
height:250px;
z-index:2;
}
#toolbar {
width:100%;
height:49px;
border-bottom:1px solid black;
background-color:red;
}
#toolbar-content {
width:100%;
height:200px;
background-color:orange;
}
I figure it doesn't work on the Android browser because it is deciding to ignore the toolbar's higher z-index, since it's in an element with a lower z-index.
Either way, does anyone know how I might be able to change this so that it would work on the Android browser, and/or are there other layout schemes I can use to achieve what I desire through only HTML/CSS?
I tested your example in Emulator, try add:
z-index: 2;
to your #scroller:
#scroller {
position:absolute;
top:0;
width:100%;
height:300px;
overflow:auto;
z-index: 2; // NEW
}
Worked fine for me
Why do you need z-index on #main-content? If you could just skip it than it would work even without additional z-index on #scroller.
Related
I am making a web app that is adapted/responsive to mobile. I have a toolbar that is positioned on the right side of the screen on my computer browser, and it is supposed to be placed fixed at the bottom of the screen on mobile. The strange thing is, when it is opened using an iPhone, the toolbar appears properly fixed at the bottom, but when I open the app on an Android device, such as my Samsung Galaxy S5, the toolbar is not appearing at all. Doing some testing, when I changed my styling to be relative instead of fixed, the toolbar is displayed in the same position in the middle of the screen on both iPhone and Android. What do you think the issue may be?
Here is the code:
<div class="col-sm-2">
<div class="sidebar-nav-right">
<div class="navbar navbar-default navbar-style" role="navigation">
<div class="nav">';
<a class="brand font-26 block brand-color">Tools</a>
<ul class="nav navbar-nav center">
<li><a data-toggle="modal" data-target="#newgroup-modal" class = "font-16">Create Group</a></li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</div>
</div>
</div>
.sidebar-nav-right{
width: 100%;
position: fixed;
bottom: 0px;
border-top: 1px solid black;
}
This styling is inside a media query for smaller screen sizes and, as stated above, is adapting on a mobile device of one brand so I know there isn't a problem with the media query.
If add {left: 0} can't solve it, I guess maybe the parent node of .sidebar-nav-right have the transform; then the position origin has been reset.
this is a common problem on older Android browsers. Simply add -webkit-backface-visibility: hidden; to the fixed element.
There are two ways to fix this. See this article by Brad Frost for a list of Javascript solutions: http://bradfrost.com/blog/mobile/fixed-position/
Or try the above mentioned fix by Ben Frain: https://benfrain.com/easy-css-fix-fixed-positioning-android-2-2-2-3/
See this CodePen by Ben Frain as well: http://codepen.io/benfrain/full/wckpb
I think #GoreWang's comment is spot on. You should try the following 2 things:
(1) With fixed position, sometimes not having a left property set causes the fixed element to not appear when the page loaded. Try adding the following:
.sidebar-nav-right {
left: 0;
}
(2) Add following code to your fixed element:
.sidebar-nav-right {
transform: translateZ(0);
-webkit-transform: translateZ(0);
}
This forces Chrome to use hardware acceleration to continuously paint the fixed element and avoid this bizarre behavior.(Known bug)
I'm having some issues getting the 'overscroll glow' to work on a scrollable div.
The first problem is finding answers or documentation on this because this thing has a lot of names, I'm not entirely sure what the correct term is and most of them I tried confuse google (i get a lot of results for 'overflow:auto;' etc). So for clarity, here's an image of the effect I'm looking for:
Anyway, my problem is this: I did have this effect when my html/body elements were scrollable but when I moved things to divs (in this case the .content element), it stopped working.
Something like this:
html, body {
overflow: hidden;
width:100%;
height:100%;
margin:0;
padding:0;
}
.appbar {
position: absolute;
top:0; left:0; right:0;
height:56px;
background-color:#ccc;
}
.content {
position: absolute;
top:56px; left:0; right:0; bottom:0;
overflow-x:hidden;
overflow-y:auto;
-webkit-overflow-scrolling: touch;
}
.make-it-scrollable {
height:200%;
}
<body>
<div class="appbar"></div>
<div class="content">
<div class="make-it-scrollable"></div>
</div>
</body>
On iOS I get the elastic 'rubber banding' effect when I try to scroll past the content (thanks to the -webkit-overflow-scrolling) but on Android I get nothing.
Is this by design? (meaning: is the overscroll effect disabled or 'not implemented' for divs with overflow:x?
Or am I missing something?
Oh btw I'm testing this on Android 5.1 with the latest Chromium based webview (it's a cordova app)
So here is an interesting situation I have come across.
You are on Chrome for android, when you scroll the body the address bar runs away and hides. Great!
Now you want to add a footer to your page that sticks to the bottom. You do the following:
html {
margin:0;
padding:0;
height:100%;
}
body {
margin:0;
padding:0;
height:100%;
}
#contentWrap {
margin:0;
padding:0;
padding-bottom:4em;
min-height:calc(100% - 4em);
position:relative;
}
#footer {
margin:0;
padding:0;
height:4em;
width:100%;
position:absolute;
bottom:0;
background:#262626;
}
<html>
<body>
<div id="contentWrap">
<div id="footer">
</div>
</div>
</body>
</html>
This works brilliantly, the footer will always stick to the bottom of the page regardless of content size or view-port scale.
However! Running this on a mobile design and testing in Chrome Android I found that setting the body to an explicit size, it will only scroll "content within" causing the address bar to stick around. Overflowing content is just set to default scroll in other words.
Noticing this I tried changing it to min-height so that it will always either be the size of the view-port if no content is available to fill it, or change height if there happens to be many lines of content.
Doing this however causes the contentWrap to base its height on the content rather than the parent element ie. <body>. So your footer now floats instead of sticking to the bottom.
I have played around with many combinations and cant seem to get what I want. Seems you have to live with either a sticky address bar OR a floating footer.
Please any ideas or thoughts on this would be appreciated.
Thanks but no that does not work in this situation.
Earlier today though whilst working on another project it hit me like a wet fish.
Remove dimensions from <html>.
Then add 100vh to your <body> instead of 100%
(making sure to only target mobile devices and not desktops)
Then it works perfectly! xD
Though Chrome is awesome imo. The little address hide on scroll has given me numerous headaches over the past few months.
When i make footers,
I code in css
.footerdiv{position:fixed; left:0; right:0; bottom:0; height:60px; z-index:777}
That does the trick.
Z-index keeps it above all the other elements. Position:fixed keeps it from moving as you scroll. and the left,right,bottom keep it sized perfectly.
Style as you wish.
Hope this helps.
Issue shows up on Android browsers when the following are on a page:
A div element with a size larger than the device's viewport. (I used 1200px.)
One or more other div elements with either left:0; right:0; margin:auto; or left:50%; margin-left:-100px style centering.
The issue is that the "centered" div elements actually aren't. They have an offset to the left (or top if centering vertically). The problem shows up on Android devices in both Chrome and Dolphin (WebKit). It does not show up on desktops (tested Chrome, FireFox, Safari, and IE).
Here is some example CSS:
body{ margin:0; padding:0; }
.wide-element {
position:absolute;
height:800px; width:1200px;
left:50%; margin-left:-600px;
background:url(1200px-wide.png);
}
.fixed-1, .fixed-2, .absolute-1, .absolute-2 { height:200px; width:200px; }
.fixed-1 {
position:fixed; margin:auto;
left:0; right:0; top:0; bottom:0;
background:rgba(0, 0, 255, .5);
}
.fixed-2 {
position:fixed; margin:-105px 0 0 -105px;
left:50%; top:50%;
border:5px solid blue;
}
.absolute-1 {
position:absolute; margin:auto;
left:0; right:0; top:0; bottom:0;
background:rgba(255, 0, 0, .5);
}
.absolute-2{
position:absolute; margin:-105px 0 0 -105px;
left:50%; top:50%;
border:5px solid red;
}
And the HTML:
<body>
<div class="wide-element"></div>
<div class="fixed-1"></div>
<div class="fixed-2"></div>
<div class="absolute-1"></div>
<div class="absolute-2"></div>
</body>
I added the position:fixed pair to contrast with the position:absolute pair. As you can see in the following screenshot, the fixed divs are both at the actual center of the screen, while the absolute divs are slightly up and to the left of the center of the layout. The most problematic part is that this offset causes elements on the left side of the screen to be cut off, and unreachable.
I'd like to know why (exactly) is this happening (and why only on mobile devices), but the real question is:
How can I reliably center a div element that might be larger than the viewport, without Android devices making parts of the page unreachable?
This is a provisional answer to my own question.
Adding a <meta name="viewport" content="width=1200"> line to the head section seems to force the browser to set the viewport to the specified size. However, since this isn't a true fix, and others may need a more flexible solution, I'm leaving it open for a more complete answer.
I've got a web page with some text inputs. The Android browser (at least on Android 2.3.4 which is all I've got now) seems to overlay its own control over the input on the page on focus.
The problem is that the overlaid control is a white rectangle and it looks ugly. Is there a way to disable it, or style it somehow?
UPDATE:
Here is an example from the Android emulator:
The rounded corners and the background are lost. On the actual device, I don't even see a border around the control.
I should probably mention that I'm using jQuery Mobile. My test device is an HTC Evo 4G.
Related questions:
Input has different style on focus
Input-Elements in WebViews always have the same style if highlighted on HTC Devices
Finally, I solved this problem for Android 2.3 devices.
It is not possible to really remove the overlay, but it is possible to move the overlay outside the viewport.
The overlay tries to position itself to the same position as the input field.
It copies the width and the position offset which you assign with
position:relative
and
top:-10000px
But the overlay does not copy the position offsets which are assigned through
-webkit-transform: translate3d()
This causes several issues with JS libraries like iScroll.
But this also helps us to hide the overlay:
input[type="password"], input[type="text"]{
position:relative;
top:-10000px;
-webkit-transform: translate3d(0, 10000px, 0);
}
You place the input field outside the viewport. Overlay positions itself beside it. Now you use translate3d() for moving it to the old position.
We use this solution already in our mobile web framework "qooxdoo Mobile":
http://demo.qooxdoo.org/devel/mobileshowcase/index.html#%2Fform
Following code will remove tap highlight - [Android 4.0.3]
input{
-webkit-user-modify: read-write-plaintext-only;
-webkit-tap-highlight-color:#3072af;
}
Not sure this is a working solution and answer, but my inputs started playing along on Android after commenting out these, which all created havoc on my Android (HTC2.3) text inputs and selects
/* really bad */
-webkit-backface-visibility: hidden;
/* your normal bad */
-webkit-transform: rotateY(0deg);
-moz-transform: rotateY(0deg);
transform: rotateY(0deg);
If you want to style default inputs, I'm using these:
/* native placeholder styling */
::-webkit-input-placeholder {
color:#555555;
}
:-moz-placeholder {
color:#555555;
}
.inField label {
color:#555555;
cursor: text;
}
After commenting out the first webkits, Android is working ok for me. I'm overriding plenty of other stuff, too though.
Also check out the screenshot below:
What I did with my inputs is create a listview, put all my inputs into list items and strip all input-JQM-CSS. This should give you a transparent input sitting on top of a listview item, which I think looks really good. You can also add labels to the inputs, my example is set up to work with the inField label plugin, so you have all these classes on board already, too.
The screenshot is from my Android HTC 2.3.5 and shows an input type="search". It's a listview search filter, which I stripped of most JQM-css. I have removed it from the listview further down, placed it into my form-list, added a label (can't see if active) and stripped all CSS, including icons.
Here is an example of how I'm doing my list-forms:
<ul data-role="listview" data-inset="true" class="inputList">
<li data-role="fieldcontain" data-icon="false" class="inField ui-btn ui-corner-top" data-theme="c">
<div class="ui-btn-inner" aria-hidden="true"><div class="ui-btn-text">
<label for="item">item</label>
<input type="text" name="item" id="item" />
</div></div>
</li>
<li data-role="fieldcontain" data-icon="false" class="inField ui-btn ui-corner-bottom" data-theme="c">
<div class="ui-btn-inner" aria-hidden="true"><div class="ui-btn-text">
<label for="item2">item2</label>
<input type="text" name="item2" id="item2" />
</div></div>
</li>
</ul>
CSS:
.inputList li div.ui-btn-inner {
background: none;
border-bottom-width: 0px;
border-left-width: 0px;
border-right-width: 0px;
}
.inputList label {
margin: 3px 0 0 !important;
}
// styling of text inputs!
.inputList input.ui-input-text, .inputList textarea.ui-input-text {
width: 93%;
margin-left: 1%;
padding: 0.6em 0;
text-indent: 80px; /* hard-coded - doesn't work on Android */
border-width: 0px;
background: transparent;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
-moz-border-radius:0px;
-webkit-border-radius: 0px;
border-radius: 0px;
}
.inputList .ui-li-divider:not(.input-divider), .inputList .ui-li-static, .inputList .ui-li-has-alt, .inputList .ui-link-inherit, .inputList .ui-btn-icon-notext .ui-btn-inner {
padding: 0px !important;
}
// labels, from inField label plugin, but not active
.inField {
position:relative
}
.inField label {
line-height: 2.25em;
vertical-align: middle;
position:absolute;
left:8pt;
width: inherit !important;
}
I hope this is all CSS. If you are trying to set this up and it looks crummy, let me know.
Working like this looks very nice on my HTC 2.3.4 My CSS still needs some polishing. I need to decrease the inputs width and align: center, so the borders of the below list item stay visible.
Other than that this would be a nice solution to crummy Android inputs. Just strip all JQM-CSS and put a listview-li behind.
Here is my code:
input {
-webkit-user-modify: read-write-plaintext-only;
-webkit-tap-highlight-color: rgba(255,255,255,0);
}
I'm just taking a guess here, and you've probably already tried, but
-webkit-appearance: none;
may do the trick. I've not even got an android device, but on iphone that sorts out most input related styling problems as it strips out the default browser applied styling completely. Worth a shot anyway!
-webkit-user-modify: read-write-plaintext-only;
-webkit-tap-highlight-color:rgba(0,0,0,0);
outline-style: none;
This will working fine in Android 4.0 but when you use this code for numeric Input field doesn't support bcoz of read-write-plaintext-only, i got this problem, please anyone suggest.
#czuendorf, May 13 at 13:53:
Worked for me too (also Android 4.0).
However... if you use an input with type="number" then the numeric keyboard does not pop-up anymore when you enter the field, but the regular keyboard is shown instead.
If you remove -webkit-user-modify, then the right keyboard is shown again, but the input element is shown with a border while it is being edited.
In my case the input overlay messed up the layout (moved some content down and right), but this does not happen anymore with this new css code.
I confirm the macnerd analysis of the czuendorf patch. These behaviors vary widely from one android version to another. I tested it on a real Htc device with android 4.0.3 and the outline disappeared (great!) but it opens some serious keyboard issues (I see that the single keypress is not shown in the field, and other strange behaviors...). In the emulator no keyboard issue occur. I've not found any solution for the real device. It's a shame!