I've made a JS animation that I want to be the background of my homepage: http://geotheory.co.uk/. But I'm quite new to web development and unclear how to stop the canvas element being an 'inline' object on the page and set it behind other HTML elements. Very grateful for advice. The HTML is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>geotheory.co.uk</title>
<style>
canvas:focus{outline:none;}
* {
margin: 0;
padding: 0;
}
h1 {color:#fff;}
p {color:#fff;}
</style>
</head>
<body id="home" bgcolor="black">
<!-- style="overflow:hidden;" -->
<h1>Heading</h1>
<p>paragraph 1</p>
<p>paragraph 2</p>
<script src="processing-1.4.1.min.js"></script>
<div id="canvasContainer">
<canvas data-processing-sources="rectangles.pde"></canvas>
</div>
</body>
In 2018 I'd use
html, body {
margin: 0;
height: 100%;
}
canvas {
width: 100%;
height: 100%;
display: block;
position: fixed;
top: 0;
left: 0;
z-index: -9999;
}
Here's why:
I used to recommend canvas { width: 100vw; height: 100vh; ...} but sadly mobile browsers broke vh so it's useless and will apparently be useless forever. See this blog post.
display: block; fixes some issues with scrollbars on certain browsers. Some pages use html, body { overflow: none; } but again that doesn't make sense if your page ends up needing to be taller than the screen/window.
position: fixed; makes the canvas position relative to the top of window so it won't scroll with the page. If you use position: absolute then the canvas will scroll off the top if the page is taller than the screen/window. For example this page.
top: 0; left 0; puts it at the top left. Without that it would default to it's default position which is inside the body's margins. Often this is solved by setting body { margin: 0; } but generally that means you end up needing some other container to add a margin back in otherwise your normal content gets positioned at the edge of the window.
z-index: -9999; is there to try to force it further back than anything else just in case the page itself is using some negative values for z-index
Here's an example as a snippet
var ctx = document.querySelector("canvas").getContext("2d");
function resize(canvas) {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (width != canvas.width || height != canvas.height) {
canvas.width = width;
canvas.height = height;
}
}
function render(time) {
time *= 0.001;
resize(ctx.canvas);
ctx.save();
var w = ctx.canvas.width;
var h = ctx.canvas.height;
var hw = w / 2;
var hh = h / 2;
ctx.clearRect(0, 0, w, h);
ctx.strokeStyle = "red";
ctx.translate(hw, hh);
ctx.rotate(time * 0.1);
for (var ii = 0; ii < 100; ++ii) {
ctx.rotate(Math.sin(time * 0.1) * 0.2);
ctx.strokeRect(-hw, -hh, w, h);
ctx.scale(0.9, 0.9);
}
ctx.restore();
requestAnimationFrame(render);
}
requestAnimationFrame(render);
html, body {
margin: 0;
height: 100%;
}
canvas {
width: 100%;
height: 100%;
display: absolute;
position: fixed;
top: 0;
left: 0;
z-index: -9999;
}
<canvas></canvas>
<pre>
some content that is in front of the canvas
Let's
try
to
make
sure
it's
long
enough
that
we
can
scroll
down
the
page
so
we
can
see
that
position: fixed;
is
a
better
choice
than
position: absolute;
</pre>
And here's an example outside SO so you can view it easier full size.
iframes work as well
Note that there's the issue that if your canvas animation is interactive the elements in front of the canvas will eat the mouse/touch events. There's no easy solution I know of for that. You can mark everything but that canvas/iframe as pointer-events: none and mark the canvas/iframe as pointer-events: auto but then you run into the issue that no text on your page can be selected and no links can be clicked. You could then say set <a> tags to have pointer-events: auto so links work but I'm sure there will be issues here and there depending on what info is on your page (trying to copy an email address, or a location address, etc...)
canvas {
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:-1;
}
Related
I'm currently trying something out which i saw on another website.
Imagine many pictures at the same position at the bottom of the website. Now when you scroll up - it will scroll every picture one bye one up - when done you will get eventually to the footer.
I already tried position: sticky etc. but it did not worked as I wanted.
Can someone help me? I would be so happy!
.poster-middle {
width: 100%;
height: 100%;
top: 0;
position:-webkit-sticky;
position:sticky;
}
.poster-middle-img {
margin-top: 500px;
}
.poster-left {
width: 100%;
height: 100%;
top: 0;
position:-webkit-sticky;
position:sticky;
}
.poster-left-img {
margin-top: -700px;
}
.poster-right {
width: 100%;
height: 100%;
top: 0;
position:-webkit-sticky;
position:sticky;
}
.poster-right-img {
margin-top: -700px;
}
<div class="poster-middle"><div class="poster-middle-img"><img src="img/1.jpg"></div></div>
<div class="poster-left"><div class="poster-left-img"><img src="img/2.jpg"></div></div>
<div class="poster-right"><div class="poster-right-img"><img src="img/3.jpg"></div></div>
right now everything is scrolling up together
You can achive this with pure css.
The trick is to use the sticky attribute of the position property and define the bottom property. This way all images are sticking to the bottom of the page. If the value of the bottom property is less than the image height, the top of all the images are visible all the time. The images below the first one are outside of view (technically) but will be visible because of the sticky attribute. Margin-bottom defines the margin between the images.
When the user starts scrolling, one image after the other is scolling into the view and is released from the position at the bottom and will scroll freely to the top.
position: -webkit-sticky;
position: sticky;
bottom: -200px;
margin-bottom: 300px;
The rest is normal positioning.
I created a little fiddle to show a full example. You can build your solution from there very easily.
I said CSS only, but used javascript in the fiddle. The code is only to give all elements a z-index. You can do this when generating the page or with nth-child in the css. But I didn't want to do that. Call it laziness ;)
You can use jquery to do this
var src = ['url_image1.jpg', 'url_imafe2.jpg'];. // Array of source of images
var i = 0;
$(document).ready(function() {
$(window).bind('mousewheel',function() {
$('#imgs').hide().delay(1000).fadeIn();
if (i==1){
$('#imgs').attr('src', src[i]);
i=0;
}
else {
$('#imgs').attr('src', src[i]);
i=1;
}
});
});
<style>
div{height:500px}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img id="imgs" style="display: none;margin-left: 100px;margin-top: -150px; position: relative" src="https://i.ytimg.com/vi/vl8IxeB0ss4/maxresdefault.jpg">
</div>
function set_bg_container_height() {
let e = document.getElementById("bg_container");
e.style.height = window.innerHeight + "px";
}
window.onresize = function() {
set_bg_container_height();
}
set_bg_container_height();
body {
margin: 0;
padding: 0;
}
#bg_container {
width: 100%;
height: 100%;
/* will be overruled by javascript */
}
#bg_image {
object-fit: cover;
width: 100%;
height: 100%;
}
<div id="bg_container">
<img id="bg_image" src="eyes1.jpg">
</div>
I want an image in the background just large enough that it always covers the window.
Without javascript I get:
Or other unwanted behaviour. Is it possible without using javascript?
You can also put background-position property in your css file which has value of x-axis and y-axis along with center you can do it like that background-position:center; or like background-position:x-axis y-axis or background-position:aSingleValueForBothAxis,
I sure hope this will solve your problem
I want to show only a percentage of an image (say, the top half), but in a responsive way so that resizing the viewport doesn't affect what portion of the image is shown.
JSFiddle attempt
The only solutions I've found rely on using a fixed height for the image (say, 200px) rather than a %age, but this isn't responsive. As you shrink the viewport, more and more of the image shows until you eventually see the entire image.
Note: My JSFiddle example is using the bootstrap class img-responsive, which adds the following CSS properties:
display: block
max-width: 100%;
height: auto
You can also grab the middle divider/handlebar in the JSFiddle and move it around to see the effect on the image.
What can be done to meet my requirements? Is it even possible without JavaScript and with browser support down to IE9?
Here, I threw this together for you: https://jsfiddle.net/qse2LL4b/4/
function showPart(img, offsetTop, offsetLeft, width, height){
var src = img.src;
$(img).replaceWith("<canvas id='cnvs' style='max-width:100%;'></canvas>");
var canvas = document.getElementById('cnvs');
canvas.height = height;
canvas.width = width;
var ctx = canvas.getContext("2d");
var img = new Image();
img.onload = function(){
ctx.drawImage(this, offsetLeft, offsetTop, width, height, 0, 0, width, height);
};
img.src = src;
}
It takes the source of your image and crops it and replaces it. You can add the im-responsive class to the "canvas" element in the function if you want.
Maybe like this
body {
background: gray;
}
div {
display: inline-block;
overflow: hidden;
}
div img {
position: relative;
margin-top: -50%;
transform: translateY(50%);
}
<div>
<img class="img-responsive" src="http://icons.iconarchive.com/icons/mazenl77/I-like-buttons-3a/512/Cute-Ball-Go-icon.png" class="img-responsive" />
</div>
You can use a pseudo-element :after in addition to position: absolute.
div:after {
content: "";
position: absolute;
height: 50%;
width: 100%;
top: 0;
left: 0;
background-color: #ffffff
}
Fiddle: https://jsfiddle.net/qse2LL4b/3/
I would like a responsive page which contains canvas elements inside a div. I should be able to simply wrap a canvas element inside another block element, and give that canvas a relative width. Although this method works in Chrome, Firefox, Safari, and Opera, or course IE has to be the fly in the ointment! I'm not even trying versions older then IE9--this simple code example does not work as expected in IE9:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test IE9 Canvas Height</title>
<style>
body {
margin: 0;
padding: 0;
}
#container {
position: relative;
padding-top: 32%;
background-color: #88f;
}
.instruments {
position: absolute;
bottom: 0%;
width: 100%;
padding-bottom: 16%;
background-color: #8f8;
}
#circle {
position: absolute;
left: 42%;
width: 16%;
}
</style>
</head>
<body>
<div id="container">
<div class="instruments">
<canvas id="circle"></canvas>
</div>
</div>
<script>
var canvas = document.getElementById("circle");
var ctx = canvas.getContext("2d");
// Default canvas is 300x150, so make it square
canvas.height = canvas.width;
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
</script>
</body>
</html>
This simple page should render a blue block of height 32% of the body width, and then have another block in green overlapping the bottom 1/2. Inside the inner div is a canvas element which does not explicitly set the height and width--so that it can remain fluid for various window/body widths. The canvas should draw a round red circle, with the height completely contained within its containing div. Works great in every other browser except IE9 (and except IE10 too I think).
Even if I do specify a canvas size,
<canvas id="circle" width="300" height="300"></canvas>
it still doesn't work.
Is there something I am doing wrong, or is there a better method to achieve this goal? I do not want to style or code pixel or point sizes, and would prefer to avoid a javascript IE hack. Thank you
Honestly your tone about IE being bad again makes me not want to help you all that much. Dial it down next time.
Your behavior here is kind of undefined, because canvass nature is to "stretch" their content and there is nothing in your code keeping your canvas square so no reason for it to scale evenly... You can see this for yourself by giving the canvas a background color... the short version is add:
height: 100%
to the canvas' css to make it work the way you want it to... hope this helps -ck
UPDATE:
I read your comment and you don't seem to understand that setting the canvas.width and canvas.height only changes the size of the internal "drawing surface" of the element. When you set the element's style (the default is auto) you are setting the display surface's dimensions. The problem that you are running into is that you are expecting the browser to preserve the canvass internal dimensions when one of it's style dimension members is set to auto and the other is not, like how it works with an img tag. Chrome & Firefox seem to behave this way. IE however is just letting your actual dimension come through, so in your case its as if you set the height to 300px. I'm not sure if there is a "spec correct" approach to this yet, but it seems like all implementations are converging on your preferred behavior.
Anyhow, the solution to your problem is to use an img tag since that tag will behave correctly and just use a data uri to get your canvas image into it:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test IE9 Canvas Height</title>
<style>
body {
margin: 0;
padding: 0;
}
#container {
position: relative;
padding-top: 32%;
background-color: #88f;
}
.instruments {
position: absolute;
bottom: 0%;
width: 100%;
padding-bottom: 16%;
background-color: #8f8;
}
#circle {
position: absolute;
left: 42%;
width: 16%;
}
</style>
</head>
<body>
<div id="container">
<div class="instruments">
<img id="circle" src=""/>
</div>
</div>
<script>
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
// Default canvas is 300x150, so make it square
canvas.height = canvas.width = 300;
ctx.beginPath();
ctx.arc(canvas.width/2, canvas.height/2, canvas.width/2, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
var img = document.getElementById('circle');
img.src = canvas.toDataURL();
</script>
</body>
</html>
That will give you the effect you were looking for without need for any further hacks...
On a side note, your css technique of using padding to "size" an element with a percent is a little fragile (like all % based css techniques). If I were using a % based css layout, I would probably using something like this:
<style>
html, body {
margin: 0;
padding: 0;
height:100%;
}
#container {
height: 33%;
background-color: #88f;
}
.instruments {
height:50%;
background-color: #8f8;
position:relative;
top:50%;
}
#circle {
display:block;
margin:auto;
width:auto;
height:100%;
}
</style>
you can see the full thing (with modified css) in action here: http://jsbin.com/ajoTUZA/2/quiet
I hope that this helps -ck
Why doesn't my slideshow header change according to my CSS attributes?
This is basically how my slideshow header works
<div id="Slideshow">
<img src="image/s1.jpg" name="slide">
<script type="text/javascript">
<!--
var step = 1
function slideit() {
document.images.slide.src = eval("image" + step + ".src")
if (step < 5)
step++
else
step = 1
setTimeout("slideit()", 2500)
}
slideit()
//-->
</script>
</div>
As you can see i declared the CSS covering the slideshow as "Slideshow"
This is my "slideshow" CSS
#Slideshow
{
position:absolute;
top:121px;
left:0%;
width:100%;
margin: 0px;
height:150px;
}
Despite adding the width/height attributes, the slideshow does not change visually.
I see these properties working fine. I set this up:
The Fiddle
So you can see it working, it's positioning 121 pixels from the top, and I made the background black so you can see it's the right height of 150px.
I also went ahead and cleaned the formatting on the CSS a bit by giving it spaces and getting rid of some leftover characters next to the Zeros'
#Slideshow {
background: #000;
position: absolute;
top: 121px;
left: 0;
width: 100%;
margin: 0;
height: 150px;
overflow: hidden;
}
I should also mentioned that I added the overflow: hidden; because the image I had was too big so the overflow: hidden; prevents the overflow of the element (in this case an image) from it's parent container.
Let me know if this clarified your question.