I have a very simple CSS 100% example, that logically as I understand it, should work, but doesn't. Can someone please explain why?
HTML:
<div id="header">header</div>
<div id="nav">Nav</div>
<div id="title">title</div>
<div id="content">
Content
</div>
CSS:
html {
height:100%;
padding: 0;
margin: 0;
}
body {
height: 100%;
padding: 0;
margin: 0;
}
#header {
background-color:red;
padding: 0;
margin: 0;
}
#nav {
background-color:gray;
padding: 0;
margin: 0;
}
#title {
background-color:azure;
padding: 0;
margin: 0;
}
#content {
background-color:antiquewhite;
height:100%;
padding: 0;
margin: 0;
}
To my understanding, there should be no vertical scroll bar. Yet one appears.
Here is a fiddle to demonstrate: http://jsfiddle.net/codeowl/9wABW/
Thank you for your time,
Regards,
Scott
UPDATE:
Here is what I ended up doing:
I developed a stack and fill approach as follows. Unfortunately fiddle has an issue with me trying to access the window in java script, so I can only paste the code:
CSS:
#header {
background-color:red;
}
#nav {
background-color:gray;
}
#title {
background-color:azure;
}
#content {
background:green;
}
HTML:
<div id="header" class="stack-y">header</div>
<div id="nav" class="stack-y">Nav</div>
<div id="title" class="stack-y">title</div>
<div id="content" class="fill-y">
<div data-role="splitter"
data-panes="[
{ scrollable: false, collapsible: true, size: '300px' },
{ scrollable: false, collapsible: true }
]"
class="fill-y">
<div>
Left Pane
</div>
<div>
Right Pane
</div>
</div>
<div class="stack-y">Test Content</div>
</div>
Java Script:
$(document).ready(function () {
var fResizeLayout = null;
fResizeLayout = function() {
var aFillElements = $('.fill-y');
$.each(aFillElements, function (i, e) {
var p = null,
iPY = 0,
iY = 0,
iH = 0;
e = $(e);
p = e.parent();
if (p.prop('tagName') === 'body') { iPY = $(window).height(); }
else { iPY = p.innerHeight(); }
e.siblings('.stack-y').each(function () {
iY += $(this).outerHeight(true);
});
iH = (iPY - iY - parseInt(e.css('border-top-width'), 10) - parseInt(e.css('border-bottom-width'), 10));
e.height(iH);
});
kendo.resize($('#content'));
};
kendo.init($('#content'));
fResizeLayout();
$(window).on('resize', function () {
if (this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function () {
$(this).trigger('resizeEnd');
}, 200);
});
$(window).on('resizeEnd', function () {
fResizeLayout();
});
});
Of course you will need to include the kendo libraries for the kendo part to work.
<link href="http://cdn.kendostatic.com/2013.3.1119/styles/kendo.common.min.css" rel="stylesheet" type="text/css" />
<link href="http://cdn.kendostatic.com/2013.3.1119/styles/kendo.default.min.css" rel="stylesheet" type="text/css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdn.kendostatic.com/2013.3.1119/js/kendo.all.min.js"></script>
Without the keno libraries:
HTML:
<div id="header" class="stack-y">header</div>
<div id="nav" class="stack-y">Nav</div>
<div id="title" class="stack-y">title</div>
<div id="content" class="fill-y">
Test Fill Content
</div>
<div class="stack-y">Test Stacked Content</div>
Java Script:
$(document).ready(function () {
var fResizeLayout = null;
fResizeLayout = function() {
var aFillElements = $('.fill-y');
$.each(aFillElements, function (i, e) {
var p = null,
iPY = 0,
iY = 0,
iH = 0;
e = $(e);
p = e.parent();
if (p.prop('tagName') === 'body') { iPY = $(window).height(); }
else { iPY = p.innerHeight(); }
e.siblings('.stack-y').each(function () {
iY += $(this).outerHeight(true);
});
iH = (iPY - iY - parseInt(e.css('border-top-width'), 10) - parseInt(e.css('border-bottom-width'), 10));
e.height(iH);
});
};
fResizeLayout();
$(window).on('resize', function () {
if (this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function () {
$(this).trigger('resizeEnd');
}, 200);
});
$(window).on('resizeEnd', function () {
fResizeLayout();
});
});
Credit to Carlos for the resizeEnd part: https://stackoverflow.com/a/12692647/2109254
Thanks to all those that contributed.
Hopefully this can help someone else.
Regards,
Scott
Edit
This will give exactly the layout you are looking for, using display:table-row in the wrapped content.
html {
height:100%;
padding: 0;
margin: 0;
}
body {
height: 100%;
padding: 0;
margin: 0;
}
#header {
background-color:red;
padding: 0;
margin: 0;
display: table-row;
height:1px;
}
#nav {
background-color:gray;
padding: 0;
margin: 0;
display:table-row;
height:1px;
}
#title {
background-color:azure;
padding: 0;
margin: 0;
display:table-row;
height:1px;
}
#content {
background:green;
padding: 0;
margin: 0;
display:table-row;
}
#wrapper {height:100%;width:100%;margin:0;padding:0;display:table}
<div id="wrapper">
<div id="header">header</div>
<div id="nav">Nav</div>
<div id="title">title</div>
<div id="content">
Content
</div>
</div>
Check your updated fiddle
You need a wrapper for the elements, depending on your specific layout you might want to play with table css attributes (display: table-row etc).
<div id="wrapper">
<div id="header">header</div>
<div id="nav">Nav</div>
<div id="title">title</div>
<div id="content">
Content
</div>
</div>
html {
height:100%;
padding: 0;
margin: 0;
}
body {
height: 100%;
padding: 0;
margin: 0;
}
#header {
background-color:red;
padding: 0;
margin: 0;
}
#nav {
background-color:gray;
padding: 0;
margin: 0;
}
#title {
background-color:azure;
padding: 0;
margin: 0;
}
#content {
padding: 0;
margin: 0;
}
#wrapper {height:100%;margin:0;padding:0;background-color:antiquewhite;}
instead of using height:100% use height:auto..and it will work..:)
Think about what you are doing. you are telling content to be 100% of it's containing element. This would be body.
Thus, content will take up the size of the window, but you still have three other divs with height, thus total content size will = 100% (body size) + header + nav + title
If you want to fix this, you could simply make the inner contents add up to 100% and adjust the percentages to what you need. Take a look:
http://jsfiddle.net/9wABW/3/
Related
I have a search bar which would like to display onto the header on scroll, a great example is like the one on this site: https://www.indiamart.com/
Approach 1 - A simple way to do this would be to detect a scroll & add and remove a class that contains display: none;
You can have an event listener -
window.addEventListener('scroll', function() {
if( window.scrollY !== 0) {
document.getElementById('searchBar').classList.add('scrolled');
} else {
document.getElementById('searchBar').classList.remove('scrolled');
}
});
With the CSS -
.noScroll
{
background: yellow;
position:fixed;
height: 50px; /*Whatever you want*/
width: 100%; /*Whatever you want*/
top:0;
left:0;
display:none;
}
/*Use this class when you want your content to be shown after some scroll*/
.scrolled
{
display: block !important;
}
.parent {
/* something to ensure that the parent container is scrollable */
height: 200vh;
}
And the html would be -
<div class="parent">
<div class ='noScroll' id='searchBar'>Content you want to show on scroll</div>
</div>
Here's a JSFiddle of the same - https://jsfiddle.net/kecnrh3g/
Approach 2 -
Another simple approach would be
<script>
let prevScrollpos = window.pageYOffset;
window.onscroll = function() {
let currentScrollPos = window.pageYOffset;
if (prevScrollpos > currentScrollPos) {
document.getElementById('searchBar').style.top = '-50px';
} else {
document.getElementById('searchBar').style.top = '0';
}
prevScrollpos = currentScrollPos;
}
</script>
with the html -
<div class="parent">
<div id ='searchBar'>Content you want to show on scroll</div>
</div>
and css
#searchBar {
background: yellow;
position: fixed;
top: 0;
left: 0;
height: 50px;
width: 100%;
display: block;
transition: top 0.3s;
}
.parent {
height: 200vh;
}
Here's a JSFiddle of the same - https://jsfiddle.net/0tkedcns/1/
From the same example, the idea is only to show/hide once user scroll the page using inline css display property, you can do the same or at least provide a code sample so we can help you!
HTML
<div class="search-bar">
<div class="sticky-search">
Sticky Search: <input type="text" value="search" />
</div>
</div>
CSS
.sticky-search {
display:none;
position:fixed;
top:0px;
left:0px;
right:0px;
background:blue;
padding:10px;
}
JS
var searchHeight = $(".search-bar").outerHeight();
var offset = $(".search-bar").offset().top;
var totalHeight = searchHeight + offset;
console.log(totalHeight);
$(window).scroll(function(){
if($(document).scrollTop() >= totalHeight) {
$('.sticky-search').show();
} else {
$('.sticky-search').hide();
}
});
I have a razor view web page that has a div that i fill data into it in some way (lazy load, or loop, doesn't matter).
If i dont use a Layout, IE:
#{
Layout = "_Layout";
}
Then the div will use my configured height, and also shows a scrollbar if needed (using overflow: auto)
However, when i add a layout, even an empty one, i cannot seem to modify the div's height, which causes it to take all the screen from the layout to the bottom, and shows no scrolling.
What disabled my ability to change the height?
(the div im loading data into is div id container)
index.cshtml:
#{
Layout = "_Layout";
}
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 5px;
text-align: center;
width: 15%;
}
.Good {
background-color: green
}
.Bad {
background-color: red
}
#container {
background: #eee;
}
</style>
<head>
<script src="/JQuery/jquery-3.3.1.min.js"></script>
</head>
<body style="overflow: hidden;">
<div>
<div>
<h3 id="Progression"></h3>
</div>
<div id="container" style="width: 100%; height: 80%; overflow: auto;">
</div>
<div id="progress" style="display: none; height: 20%">
<h4>Loading...</h4>
</div>
</div>
</body>
_Layout.cshtml:
<!DOCTYPE html>
<style>
.main-header {
background: url(/images/bg-header.png) transparent repeat-x 0 0;
}
</style>
<html>
<head>
<meta name="viewport" content="width=device-width" />
</head>
<body>
<header class="main-header" role="banner">
<div>
<a href="/" title="Home" rel="home">
<img src="/images/COMPANY-logo.png" style="background-color:white;" alt="Home">
</a>
</div>
</header>
<div>
#RenderBody()
</div>
</body>
</html>
Empty _Layout.cshtml: (having issues with this layout as well)
<!DOCTYPE html>
<style>
.main-header {
background: url(/images/bg-header.png) transparent repeat-x 0 0;
}
</style>
<html>
<head>
</head>
<body>
<div>
#RenderBody()
</div>
</body>
</html>
Generated page (The empty layout was used):
<!DOCTYPE html>
<style>
.main-header {
background: url(/images/bg-header.png) transparent repeat-x 0 0;
}
</style>
<html>
<head>
</head>
<body>
<div>
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 5px;
text-align: center;
width: 15%;
}
.Good {
background-color: green
}
.Bad {
background-color: red
}
#container {
background: #eee;
}
</style>
<head>
<script src="/JQuery/jquery-3.3.1.min.js"></script>
</head>
<body style="overflow: hidden;">
<div>
<div>
<h3 id="Progression"></h3>
</div>
<div id="container" style="width: 100%; height: 80%; overflow: auto;">
</div>
<div id="progress" style="display: none; height: 20%">
<h4>Loading...</h4>
</div>
</div>
</body>
<script>
var pageSize = 50;
var pageIndex = 0;
var totalItemsDisplayed = 0;
$(document).ready(function() {
lazyLoadCards(0);
$('#container').scroll(function() {
var scrollTop = $(this).scrollTop();
var scrollHeight = $(this).prop('scrollHeight');
var clientHeight = $(this).prop('clientHeight');
if (scrollTop + clientHeight === scrollHeight) {
pageIndex++;
lazyLoadCards(pageIndex);
}
});
function lazyLoadCards(index) {
$.ajax({
type: 'GET',
url: '/AllCards/OnScrollEnd',
data: { "startIndex": index, "size": pageSize },
dataType: 'json',
success: function(data) {
if (data != null) {
totalItemsDisplayed += data.length;
for (var i = 0; i < data.length; i++) {
$("#container").append("<h2>" +
data[i].cardNumber +
"</h2>");
}
updateProgression();
}
},
beforeSend: function() {
$("#progress").show();
},
complete: function() {
$("#progress").hide();
},
error: function() {
alert("Error while retrieving data!");
}
});
}
function loadCards(index) {
$.ajax({
type: 'GET',
url: '/AllCards/OnScrollEnd',
data: { "startIndex": index, "size": pageSize },
dataType: 'json',
success: function(data) {
if (data != null) {
totalItemsDisplayed += data.length;
for (var i = 0; i < data.length; i++) {
$("#container").append("<h2>" +
data[i].cardNumber +
"</h2>");
}
updateProgression();
if (data.length > 0) {
loadCards(index + 1);
}
}
},
beforeSend: function() {
$("#progress").show();
},
complete: function() {
$("#progress").hide();
},
error: function() {
alert("Error while retrieving data!");
}
});
}
function updateProgression() {
$('#Progression').text("Displaying " + totalItemsDisplayed + " Cards out of " + 6930);
}
});
</script>
</div>
</body>
</html>
Visual to see current output and desired outcome:
(Note that thetext inside the gray box is just elements with some text. thats what the ajax call does)
Generated code after adding #section and #style and removing body everyone besides _Layout
<!DOCTYPE html>
<html>
<head>
<style>
.main-header {
background: url(/images/bg-header.png) transparent repeat-x 0 0;
}
</style>
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 5px;
text-align: center;
width: 15%;
}
.Good {
background-color: green
}
.Bad {
background-color: red
}
#container {
background: #eee;
}
</style>
</head>
<body>
<header class="main-header" role="banner">
<div>
<a href="/" title="Home" rel="home">
<img src="/images/COMPANY-logo.png" style="background-color:white;" alt="Home">
</a>
</div>
</header>
<div>
<div>
<div>
<h3 id="Progression"></h3>
</div>
<div id="container" style="width: 100%; height: 80%; overflow: visible;">
</div>
<div id="progress" style="display: none; height: 20%">
<h4>Loading...</h4>
</div>
</div>
</div>
<script src="/JQuery/jquery-3.3.1.min.js"></script>
<script>
var pageSize = 50;
var pageIndex = 0;
var totalItemsDisplayed = 0;
$(document).ready(function() {
lazyLoadCards(0);
$('#container').scroll(function() {
var scrollTop = $(this).scrollTop();
var scrollHeight = $(this).prop('scrollHeight');
var clientHeight = $(this).prop('clientHeight');
if (scrollTop + clientHeight === scrollHeight) {
pageIndex++;
lazyLoadCards(pageIndex);
}
});
function lazyLoadCards(index) {
$.ajax({
type: 'GET',
url: '/AllCards/OnScrollEnd',
data: { "startIndex": index, "size": pageSize },
dataType: 'json',
success: function(data) {
if (data != null) {
totalItemsDisplayed += data.length;
for (var i = 0; i < data.length; i++) {
$("#container").append("<h2>" +
data[i].cardNumber +
"</h2>");
}
updateProgression();
}
},
beforeSend: function() {
$("#progress").show();
},
complete: function() {
$("#progress").hide();
},
error: function() {
alert("Error while retrieving data!");
}
});
}
function loadCards(index) {
$.ajax({
type: 'GET',
url: '/AllCards/OnScrollEnd',
data: { "startIndex": index, "size": pageSize },
dataType: 'json',
success: function(data) {
if (data != null) {
totalItemsDisplayed += data.length;
for (var i = 0; i < data.length; i++) {
$("#container").append("<h2>" +
data[i].cardNumber +
"</h2>");
}
updateProgression();
if (data.length > 0) {
loadCards(index + 1);
}
}
},
beforeSend: function() {
$("#progress").show();
},
complete: function() {
$("#progress").hide();
},
error: function() {
alert("Error while retrieving data!");
}
});
}
function updateProgression() {
$('#Progression').text("Displaying " + totalItemsDisplayed + " Cards out of " + 6930);
}
});
</script>
</body>
</html>
You should be using sections. Sections allow you to add styles, scripts, etc. on the layout. You can't have the head and body tags anywhere except the layout page.
Empty _Layout.cshtml:
<!DOCTYPE html>
<head>
<style>
.main-header {
background: url(/images/bg-header.png) transparent repeat-x 0 0;
}
</style>
#RenderSection("Styles", required: false)
</head>
<body>
<div>
#RenderBody()
</div>
#RenderSection("Scripts", required: false)
</body>
</html>
Index.cshtml:
#{
Layout = "_Layout";
}
#section Styles {
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 5px;
text-align: center;
width: 15%;
}
.Good {
background-color: green
}
.Bad {
background-color: red
}
#container {
background: #eee;
}
</style>
}
<div>
<div>
<h3 id="Progression"></h3>
</div>
<div id="container" style="width: 100%; height: 80%; overflow: auto;">
</div>
<div id="progress" style="display: none; height: 20%">
<h4>Loading...</h4>
</div>
</div>
#section Scripts {
<script src="/JQuery/jquery-3.3.1.min.js"></script>
}
UPDATE
You need to make the following change:
<div id="container" style="width: 100%;height: 155px;overflow: scroll;display: block;">
You can't use a percentage for height unless you add position:absolute;. If you only want the vertical scroll bar, you'll need to use overflow-y:scroll; instead.
I am using this for my header that changes in a one page scroll up and down page. I noticed that it's not responsive so i am asking you if you maybe know a way to make that responsive. Like changing the 0-690 into a percentage so that it will work on mobile and also on a tv screen.
HTML
<div class="header header-1" data-visible-range="0-690">Portfolio</div>
<div class="header header-2" data-visible-range="691-2100">Services</div>
<div class="header header-3" data-visible-range="2101-">Contact</div>
CSS
.header-1 {
background-color:dimgray;
display: block;
}
.header-2 {
background-color:dimgray;
}
.header-3 {
background-color:dimgray;
}
.header {
position: fixed;
top: 0;
left: 0;
height:8vmax;
width: 100%;
display: none;
visibility:hidden;
transition: visibility .4s, opacity .4s ease-in-out;opacity:0;
font-size:4vmax;padding:1.58vmax;color:white;
}
What if, instead of basing it off pixels, you just checked to see if an element hit the top of the page, and then changed the header?
We'll call these elements "triggers." See my code below for an example of how they work.
let updateHeader = () => {
let scrollTop = $(window).scrollTop(),
triggerTitle = "Hi";
$('.trigger').each((i, el) => {
let topPos = $(el).offset().top,
distance = topPos - scrollTop;
if (distance < 0)
triggerTitle = $(el).data('title');
});
$('header h2').text(triggerTitle);
}
$(window).scroll(updateHeader);
$(window).on('touchmove', updateHeader);
body {
margin: 0;
}
#container {
height: 1000px;
}
header {
width: 100%;
position: fixed;
top: 0;
background-color: red;
}
p {
margin: 200px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<header><h2>Hi</h2></header>
<p class="trigger" data-title="section1">
trigger1
</p>
<p class="trigger" data-title="section2">
trigger2
</p>
<p class="trigger" data-title="section3">
trigger3
</p>
</div>
As you scroll down the page, each trigger hits the top of the page, and the text in the header will change to the the value of the latest trigger's data-title. You could position these triggers appropriately above each of your website's sections, so that, no matter what size the screen, the header should update at the right time. Here's a codepen.
EDIT
Try this JS instead for maximum compatibility (no es6 involved).
function updateHeader() {
var scrollTop = $(window).scrollTop(),
triggerTitle = "Hi";
$('.trigger').each(function(i, el) {
var topPos = $(el).offset().top,
distance = topPos - scrollTop;
if (distance < 0)
triggerTitle = $(el).data('title');
});
$('header h2').text(triggerTitle);
}
$(window).scroll(updateHeader);
$(window).on('touchmove', updateHeader);
I'm new and learning to code a website!
I'm trying to do this hover header that when the user scroll down, it will remain on the screen and when the user reaches Sub-Header 1, it will hover it too and changes if the user reaches Sub-Header 2(Sub-Header 1 will then disappear)
This is what I'm working on http://goo.gl/KqAM2R
Thanks in advance!
http://i.imgur.com/flT3oJ1.jpg
You need to use JavaScript to achieve this effect. SSCCE:
NewFile.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="NewFile.js"></script>
<link rel="stylesheet" type="text/css" href="NewFile.css"></head>
<body>
<header class="fixed-top">Europe</header>
<div class="much-text">doge</div>
<header class="whatever1 doge">Heatwave</header>
<div class="much-text">doge</div>
<header class="whatever2 doge">2k15</header>
<div class="much-text">doge</div>
</body>
</html>
NewFile.js:
function isElementInViewport (el, topOrBottom) {
//special bonus for those using jQuery
if (typeof jQuery === "function" && el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
if(topOrBottom == "top"){
return rect.top >= 0;
}else{
return rect.bottom <= $(window).height();
}
}
function onVisibilityChange () {
var headers = document.getElementsByClassName("doge");
var headerAbove = null;
for(i = 0; i<headers.length; i++){
$( headers[i]).css("position","");
$( headers[i]).css("top","");
if(!isElementInViewport(headers[i], "top")){
headerAbove = headers[i];
}
}
if(headerAbove != null){
$( headerAbove).css("position","fixed");
$( headerAbove).css("top","30px");
}
}
$(window).on('DOMContentLoaded load resize scroll', onVisibilityChange);
And NewFile.css
#CHARSET "UTF-8";
.fixed-top{
width:100%;
position:fixed;
top:0px;
background-color: red;
}
.whatever1{
width:100%;
background-color: green;
}
.whatever2{
width:100%;
background-color: blue;
}
.much-text{
height: 2000px;
}
.doge {
}
Thanks to authors of answers in How to tell if a DOM element is visible in the current viewport? for an inspiration. Also, I am aware that this code doesn't meet all good practices writing in js & css but OP clearly can find the idea from this one. Notice that you may need to sort headers (from the top header to the bottom header) in your own way before iterating on them in function onVisibilityChange
Try this...
HTML
<div id="page" class="page">
<div class="container">
<div class="contentheadercontainer">
<div class="fsh"><div class="firstheader">Sub header 1</div></div>
<div class="fsh"><div class="secondheader" id='secondheader'><p style='margin-left: 15px;'>Sub header 2</p></div></div>
</div>
</div>
</div>
</div>
CSS
body{
padding: 0px; margin: 0px;
}
.container{
height: 1000px;
}
.fsh{
position: absolute; width: 100%;
}
.firstheader{
height: 30px;width: 100%; position:fixed; background: #B14345; padding: 15px; color: #fff;
}
.secondheader{
border-top: 1px solid #bbb; padding: 5px 0px 5px 0px; margin-top: 300px; width: 100%; background: #B14345;color: #fff;
}
Javascript
document.addEventListener("scroll", function(){
scrollDetect();
});
function scrollDetect(){
var html = document.documentElement;
var top = (window.pageYOffset || html.scrollTop) - (html.clientTop || 0);
if(top > 235){
document.getElementById('secondheader').style.position = 'fixed';
document.getElementById('secondheader').style.marginTop = '60px';
document.getElementById('secondheader').style.width='100%';
}else{
document.getElementById('secondheader').style.position = 'inherit';
document.getElementById('secondheader').style.marginTop = '300px';
}
}
Check out this JSFiddle
I have an iframe in my HTML document and I'm having a bit of trouble.
I also have a URL bar (fixed position element) at the top of the page that should stay with the user as they scroll. That works fine. I'd like the iframe to fill the remaining space but not be covered up by the URL bar.
This is what I'm talking about. http://s75582.gridserver.com/Ls
How can I fix this so that the URL bar doesn't cover up part of the page? When I try setting padding in the body, it just creates an extra, annoying scroll bar.
Whilst you can't say ‘height: 100% minus some pixels’ in CSS, you can make the iframe 100% high, then push its top down using padding. Then you can take advantage of the CSS3 box-sizing property to make the padding get subtracted from the height.
This:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head>
<title>test</title>
<style type="text/css">
html, body { margin: 0; padding: 0; height: 100%; }
#bar { height: 32px; background: red; }
iframe {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
border: none; padding-top: 32px;
box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;
}
</style>
</head><body>
<iframe src="http://www.google.com/"></iframe>
<div id="bar">foo</div>
<body></html>
Works on IE8, Moz, Op, Saf, Chrome. You'd have to carry on using a JavaScript fallback to make the extra scrollbar disappear for browsers that don't support box-sizing though (in particular IE up to 7).
It can be done without any Javascript, works in IE7
CSS:
body {
overflow-y: hidden;
}
#imagepgframe {
width: 100%;
height: 100%;
position: absolute;
}
#wrap {
width: 100%;
position: absolute;
top: 100px;
left: 0;
bottom: 0;
}
HTML:
<div id="wrap">
<iframe id="imagepgframe" frameBorder="0" src="http://en.wikipedia.org/wiki/Internet_Explorer_7"></iframe>
</div>
To build on top of bobince's answer:
Erik Arvidsson came up with a way to (kinda, sorta) add box-sizing support to IE6/IE7. However, his solution doesn't support units other than px. Like you, I needed a percentage height, so I added support for percents.
Once you've downloaded and unzipped the zip file, open boxsizing.htc and replace the following border/padding functions:
/* border width getters */
function getBorderWidth(el, sSide) {
if (el.currentStyle["border" + sSide + "Style"] == "none")
return 0;
var n = parseInt(el.currentStyle["border" + sSide + "Width"]);
return n || 0;
}
function getBorderLeftWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Left"); }
function getBorderRightWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Right"); }
function getBorderTopWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Top"); }
function getBorderBottomWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Bottom"); }
/* end border width getters */
/* padding getters */
function getPadding(el, sSide) {
var n = parseInt(el.currentStyle["padding" + sSide]);
return n || 0;
}
function getPaddingLeft() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Left"); }
function getPaddingRight() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Right"); }
function getPaddingTop() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Top"); }
function getPaddingBottom() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Bottom"); }
/* end padding getters */
Then replace updateBorderBoxWidth and updateBorderBoxHeight with the following:
function updateBorderBoxWidth() {
element.runtimeStyle.width = "";
if (getDocumentBoxSizing() == getBoxSizing())
return;
var csw = element.currentStyle.width;
var w = null;
if (csw != "auto" && csw.indexOf("px") != -1) {
w = parseInt(csw);
} else if (csw != "auto" && csw.indexOf("%") != -1) {
var origDisplay = element.runtimeStyle.display;
element.runtimeStyle.display = "none";
w = Math.max(0, (parseInt(element.parentNode.clientWidth) - (
getBorderLeftWidth(element.parentNode)
+ getPaddingLeft(element.parentNode)
+ getPaddingRight(element.parentNode)
+ getBorderRightWidth(element.parentNode)
)) * (parseInt(csw) / 100));
element.runtimeStyle.display = origDisplay;
}
if (w !== null) {
if (getBoxSizing() == "border-box") {
setBorderBoxWidth(w);
} else {
setContentBoxWidth(w);
}
}
}
function updateBorderBoxHeight() {
element.runtimeStyle.height = "";
if (getDocumentBoxSizing() == getBoxSizing())
return;
var csh = element.currentStyle.height;
var h = null;
if (csh != "auto" && csh.indexOf("px") != -1) {
h = parseInt(csh);
} else if (csh != "auto" && csh.indexOf("%") != -1) {
var origDisplay = element.runtimeStyle.display;
element.runtimeStyle.display = "none";
h = Math.max(0, (parseInt(element.parentNode.clientHeight) - (
getBorderTopWidth(element.parentNode)
+ getPaddingTop(element.parentNode)
+ getPaddingBottom(element.parentNode)
+ getBorderBottomWidth(element.parentNode)
)) * (parseInt(csh) / 100));
element.runtimeStyle.display = origDisplay;
}
if (h !== null) {
if (getBoxSizing() == "border-box") {
setBorderBoxHeight(h);
} else {
setContentBoxHeight(h);
}
}
}
Then just use the file as you would otherwise:
.border-box {
behavior: url("boxsizing.htc");
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
Here's a pretty thorough test I put together while developing my modifications:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>box-sizing: border-box;</title>
<style type="text/css">
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: yellow;
}
body {
padding-top: 50px;
padding-bottom: 50px;
}
p {
margin: 0;
}
#header, #footer {
height: 50px;
position: absolute;
width: 100%;
overflow: hidden;
}
#header {
background: red;
top: 0;
}
#footer {
background: blue;
bottom: 0;
}
#content {
width: 100%;
height: 100%;
border: none;
margin: 0;
padding: 0;
background: black;
color: white;
overflow: auto;
position: relative;
padding-top: 40px;
padding-bottom: 40px;
}
#nested-header, #nested-footer {
position: absolute;
height: 40px;
width: 100%;
background: #CCC;
}
#nested-header {
top: 0;
}
#nested-footer {
bottom: 0;
}
#nested-content-wrap {
height: 100%;
}
#nested-floater {
height: 100%;
float: left;
width: 100px;
}
#nested-content {
height: 100%;
background: green;
color: black;
overflow: auto;
position: relative;
}
#inner-nest {
height: 100%;
position: relative;
}
#inner-head {
height: 30px;
width: 100%;
background: #AAA;
position: absolute;
top: 0;
}
#inner-content {
padding-top: 30px;
height: 100%;
overflow: auto;
}
.border-box {
behavior: url("boxsizing.htc");
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.content-box {
behavior: url("boxsizing.htc");
box-sizing: content-box;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
}
legend {
color: black;
}
form {
margin: 1em 0;
}
.wrap {
height: 100px;
background: #000;
overflow: hidden;
}
.test {
width: 100px;
height: 100%;
background: #AAA;
border-color: #EEE;
padding-left: 20px;
padding-top: 20px;
padding-bottom: 5px;
float: left;
}
.fill {
width: 100%;
height: 100%;
background: #CCC;
}
.gauge {
width: 99px;
background: white;
border-right: 1px solid green;
height: 100%;
float: left;
}
.notes {
background: #8FC561;
}
.clear {
clear: both;
}
/* 120px x 120px square; this will create a black 20px frame on the inside */
.boxtest-wrapper {
width: 100px;
height: 100px;
float: left;
background: black;
color: white;
margin: 1em;
padding: 20px;
}
#boxtest-4-container {
width: 100%;
height: 100%;
}
.boxtest {
width: 100%;
height: 100%;
background: white;
color: black;
border: 5px solid green;
overflow: hidden;
}
</style>
<script type="text/javascript">
function addBorderBox() {
var wrap1 = document.getElementById("wrap-1");
var wrap2 = document.getElementById("wrap-2");
var borderBox = document.createElement("div");
borderBox.className = "test border-box";
var borderBoxFill = document.createElement("div");
borderBoxFill.className = "fill";
var borderBoxContent = document.createTextNode("Generated border box fill");
borderBoxFill.appendChild(borderBoxContent);
borderBox.appendChild(borderBoxFill);
var gauge = document.createElement("div");
gauge.className = "gauge";
var gaugeText1 = "width: 100px";
var gaugeText2 = "height: 100%";
var gaugeText3 = "bottom should be visible";
gauge.appendChild(document.createTextNode(gaugeText1));
gauge.appendChild(document.createElement("br"));
gauge.appendChild(document.createTextNode(gaugeText2));
gauge.appendChild(document.createElement("br"));
gauge.appendChild(document.createTextNode(gaugeText3));
wrap1.appendChild(borderBox);
wrap2.appendChild(gauge);
}
</script>
</head>
<body id="body" class="border-box">
<div id="header">
<p>Header - 50px;</p>
</div>
<div id="content" class="border-box">
<div id="nested-header">
<p>Nested Header - 40px;</p>
</div>
<div id="nested-content-wrap">
<div id="nested-floater">
<p>Float - 100px;</p>
<ul>
<li>This element should never scroll.</li>
</ul>
</div>
<div id="nested-content">
<div id="inner-nest">
<div id="inner-head">
<p>Inner Head - 30px;</p>
</div>
<div id="inner-content" class="border-box">
<div style="float: right; ">
<p>The fourth square should look just like the other three:</p>
<div id="boxtest-wrapper-1" class="boxtest-wrapper">
<div id="boxtest-1" class="boxtest border-box"></div>
</div>
<div id="boxtest-wrapper-2" class="boxtest-wrapper">
<div id="boxtest-2" class="boxtest border-box"></div>
</div>
<br class="clear" />
<div id="boxtest-wrapper-3" class="boxtest-wrapper">
<div id="boxtest-3" class="boxtest border-box"></div>
</div>
<div id="boxtest-wrapper-4" class="boxtest-wrapper">
<div id="boxtest-4-container">
<!-- boxtest-4-container isn't special in any way. it just has width and height set to 100%. -->
<div id="boxtest-4" class="boxtest border-box"></div>
</div>
</div>
</div>
<p>Inner Content - fluid</p>
<ul>
<li>The top of the scrollbar should be covered by the “Inner Head” element.</li>
<li>The bottom of the scrollbar should be visible without having to scroll “Inner Head” out of view.</li>
</ul>
<p>Document Compat Mode:
<strong id="compatMode">
<script type="text/javascript">
var compatMode = document.compatMode;
if (compatMode != "CSS1Compat") {
document.getElementById("compatMode").style.color = "red";
}
document.write(compatMode);
</script>
</strong>
</p><br />
<div class="notes">
<h2>Notes</h2>
<ul>
<li>In IE6 and IE7 (and possibly IE8; untested), you'll notice a slight shift of contents that have <code>box-sizing</code> set to <code>border-box</code>. This is the amount of time it takes for box-sizing.htc to finish downloading.</li>
<li>This workaround is not live. Anything that causes a reflow or repaint will not currently trigger an update to widths and heights of <code>border-box</code> elements.</li>
<li>See http://webfx.eae.net/dhtml/boxsizing/boxsizing.html for the original solution to the IE6/IE7 <code>border-box</code> problem. box-sizing.htc has been modified to allow for percentage widths and heights.</li>
<li>To see what this example should look like without the use of box-sizing.htc, view it in Firefox or IE8.</li>
</ul>
</div>
<br class="clear" />
<form>
<fieldset>
<legend>DOM Update Test</legend>
<input type="button" value="Click to add border-box" onclick="addBorderBox(); " />
</fieldset>
</form>
<div id="wrap-1" class="wrap">
<div class="test content-box" id="content-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Content box fill</div>
</div>
<div class="test content-box" id="content-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Content box fill</div>
</div>
<div class="test border-box" id="border-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Border box fill</div>
</div>
<div class="test border-box" id="border-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Border box fill</div>
</div>
<div class="test" id="default-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Default box fill</div>
</div>
<div class="test" id="default-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Default box fill</div>
</div>
</div>
<div id="wrap-2" class="wrap">
<!-- subtract 1 from width for 1px right border -->
<div class="gauge" style="width: 129px;">width: 130px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge" style="width: 119px;">width: 120px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge">width: 100px<br />height: 100%<br />bottom should be visible</div>
<div class="gauge">width: 100px<br />height: 100%<br />bottom should be visible</div>
<div class="gauge" style="width: 129px;">width: 130px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge" style="width: 119px;">width: 120px<br />height: 100%<br />bottom should be cut off</div>
</div>
<br class="clear" />
<script type="text/javascript">
var lipsum = "<p>Lorem ipsum dolor sit amet.</p>";
for (var i = 0; i < 100; i++) {
document.write(lipsum);
}
</script>
</div>
</div>
</div>
</div>
<div id="nested-footer">
<p>Nested Footer - 40px;</p>
</div>
</div>
<div id="footer">
<p>Footer - 50px;</p>
</div>
</body>
</html>
If by covering up part of the page, you mean the page displayed in the iframe, one thought might be to add a top margin to your iframe, using the margin-top: property in CSS. This would eliminate the scroll bar given that you properly constrained the height of the iframe.
Android Kotlin Answer
For example, I am using padding for iFrame of WebView in this way:
val url = "www.stackoverflow.com"
val iframeExample = "<html><body style=\"margin: 0; padding: 0\"><iframe width=\"100%\" src=\"$url\" frameborder=\"0\" allowfullscreen></iframe></body></html>"
webView.loadData(iframeExample, "text/html", "utf-8")