Position fixed menu to top - css

I know how to use position:fixed; but I want, if the page scrolls over it, that it's on the top and on normal state lower.
.menu {
height: 30px;
width: 100%;
border-bottom: 1px solid black;
position: fixed;
top: 0px;
}

If I understand correctly, you want to make a menu fixed after it's scrolled past? If that's the case, see this question.
If that doesn't work for you, consider using code like this, assuming jQuery (actually Sprint but it's about the same for both):
var navigation = $('nav').item(0);
var navigationY = navigation.element.offsetTop;
var navClone = navigation.clone();
$(window).bind('scroll', function() {
var scrollY = (window.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop) >>> 0;
if(scrollY > navigationY) {
if(!navClone.element.parentNode || navClone.element.parentNode.nodeType !== 1) {
navigation.after(navClone);
navigation.addClass('fixed');
}
} else if(navClone.element.parentNode) {
navClone.remove();
navigation.removeClass('fixed');
}
});
which I used in a recent project, so just change $('nav') at the top to whatever you need to select your element, e.g. $('.menu').

Related

Zooming in overflow: scroll

I am trying to implement correctly scaling and zooming in css way. I created an example with scaled view. When click, the view should be zoomed and then to be able to scroll.
https://jsfiddle.net/opb5tcy8/4/
I have several issues with it:
Can I somehow get rid of the margin-left and margin-top on the .zoomed class? I did not manage to scale it without necessity to shift it with these margins.
When clicked, I can get the click position by clientX. I would like to use it to fluently scroll to the clicked position during zooming. However I can't manage the scroll to be fluent and when removing the margin-left it is kind of jumpy and not nice.
When you zoom in and move the scroll to the center and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
UPDATE:
The first part can be solved with transform-origin: 0 0. The other issues stays mostly the same as it is demonstrated.
Hm... I could say it is impossible to satisfy point 2 your condition with current browsers' support. The other are possible, as in this demo:
$(document).ready(function() {
var windowHalfWidth = $("#window").width() / 2;
var scalingFactor = 0.55;
var throtte = false;
$("#slider").click(function(event) {
//Simple event throtte to prevent click spamming breaking stuff up
if (throtte) return false;
throtte = true;
setTimeout(function() {
throtte = false;
}, 1000);
var xSelf = event.pageX - $("#window").offset().left + $("#window").scrollLeft();
if ($(this).hasClass("zoomed")) {
$("#window").animate({
scrollLeft: (xSelf / scalingFactor - windowHalfWidth)
}, 1000, "linear");
} else {
$("#window").animate({
scrollLeft: (xSelf * scalingFactor - windowHalfWidth)
}, 1000, "linear");
}
$("#slider").toggleClass("zoomed");
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
transition: 1s linear;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
As you can see, the zooming & scrolling is quite laggy, especially when the far right size is zoomed in.
The reason is simple, because jQuery and css both have their own animation loop, and they are not in sync. In order to solve this we'll need to somehow manage to do both scrolling & scaling animations with only one system, either jQuery or CSS.
Problem is: jQuery don't have a scaling feature, and css can't scroll elements. Wonderful.
If your scaling can be done with width/height though, it would be possible, using jquery width&height animate(). But if the #slider consists of many components I guess it can't be done.
So um writing an answer just to say it's impossible is kind of a let down, so I think maybe I can suggest an alternative, using dragging to scroll content (similar to the way Google map work):
var windowHalfWidth, startX, startLeft, minLeft, dragging = false,
zooming = false;
var zoomElement = function(event) {
var xSelf = event.pageX - $("#window").offset().left - parseFloat($("#slider").css("left"));
if ($("#slider").hasClass("zoomed")) {
minLeft = windowHalfWidth * 2 - 900;
var newLeft = Math.min(Math.max((-(xSelf / 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
} else {
minLeft = windowHalfWidth * 2 - 900 * 0.55;
var newLeft = Math.min(Math.max((-(xSelf * 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
$("#slider").toggleClass("zoomed");
}
$(document).ready(function() {
windowHalfWidth = $("#window").width() / 2;
minLeft = windowHalfWidth * 2 - 900 * 0.55;
$("#slider").on({
mousedown: function(event) {
dragging = true;
startX = event.pageX;
startLeft = parseFloat($(this).css("left"));
},
mousemove: function(event) {
if (dragging && !zooming) {
var newLeft = Math.min(Math.max((startLeft + event.pageX - startX), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
},
mouseup: function(event) {
dragging = false;
if (Math.abs(startX - event.pageX) < 30 && !zooming) {
// Simple event throtte to prevent click spamming
zooming = true;
$("#slider").css("transition", "1s");
setTimeout(function() {
zooming = false;
$("#slider").css("transition", "initial");
}, 1000);
zoomElement(event);
}
},
mouseleave: function() {
dragging = false;
}
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
This variation manages to get CSS to do both animation, by sacrificing the scrollbar (which is pretty ugly imo, who needs it?) and use css left instead.
So I hope if in the end you can't find a good solution, at least you have this to consider as fall back version.
I'll address the points individually and then give an example at the end.
When clicked, I can get the click position by clientX. I would like to
use it to fluently scroll to the clicked position during zooming.
In my opinion scroll animations during transitions can be a bit choppy in webkit browsers. Try balancing the animation time of the jQuery effect with the animation time of the css transition.
When you zoom in and move the scroll to the centre and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
Bring the scrollLeft property of the div#window back to 0px. Again, tweaking the animation times will make this less jerky.
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
You could use the mouseover and mouseout events to toggle a overflow:hidden css on the body.
Here's an example change to your code:
var slider = $("#slider").on('click', function(event) {
if (!slider.hasClass('zoomed')) {
// zoom back to left position
$('#window').animate({scrollLeft:'0px'});
}else{
// zoom to click position within slider
$('#window').animate({scrollLeft:event.clientX + 'px'}, 2000);
}
slider.toggleClass("zoomed");
});
/* stop window scrolling when using slider */
slider
.on('mouseover', function () {
$(document.body).css({overflow:'hidden'});
})
.on('mouseout', function () {
$(document.body).css({overflow:'auto'});
});
And an updated fiddle.

Dynamic Div Layout

I know there are a lot of posts about div layouts but what I'm looking to do doesn't seem to be on here. I am creating div's that contain dynamic text. Therefore each div is of variable length. I want these div's placed alongside each other, 4 across the page. In other words, each div occupies 25% of the width. The number of div's is variable as well so if there are more than 4 div's, then the remaining would start be placed below in the same fashion. Below is a picture of what I am trying to depict, with the gray boxes being the div's I am creating. Any help is appreciated, thank you in advance!
The div's are created in my function addSuggestion(), which is as follows:
HTML:
addSuggestion = function (counter, company_name, contact_name, street_address_1, street_address_2, phone_number, email_address) {
var output = document.getElementById('container');
var div = document.createElement('div');
var company = document.createElement('p');
company.className = "companyClass";
var contact = document.createElement('p');
contact.className = "otherClass";
var address1 = document.createElement('p');
address1.className = "addressClass";
var address2 = document.createElement('p');
address2.className = "addressClass";
var phone = document.createElement('p');
phone.className = "otherClass";
var email = document.createElement('p');
email.className = "otherClass";
if(counter%4 == 0) {
div.className = "farleft";
}
else if(counter%4 == 1) {
div.className = "centerleft";
}
else if(counter%4 == 2) {
div.className = "centerright";
}
else {
div.className = "farright";
}
if(company_name) {
company.textContent = company_name;
div.appendChild(company);
}
else {
company.textContent = "*** COMPANY INFO ***";
div.appendChild(company);
}
if(contact_name) {
contact.textContent = contact_name;
div.appendChild(contact);
}
if(street_address_1) {
address1.textContent = street_address_1;
div.appendChild(address1);
}
if(street_address_2) {
address2.textContent = street_address_2;
div.appendChild(address2);
}
if(phone_number) {
phone.textContent = phone_number;
div.appendChild(phone);
}
if(email_address) {
email.textContent = email_address;
div.appendChild(email);
}
output.appendChild(div);
}
CSS:
#container {
width: 100%;
}
#farleft {
width: 25%;
position: absolute;
float:left;
}
#centerleft {
width: 25%;
position: relative;
float:left;
}
#centerright {
width: 25%;
position: relative;
float:right;
}
#farright {
width: 25%;
position: relative;
float:right;
}
Assigning width: 25% to each div will get your 4 divs on the same row (counting there are no borders and/or margin/padding on the exterior).
float: left will keep them to the left. In order to get your 'new row' to drop down a line, <br clear="both"> would do the trick:
JSFiddle
If its a row of div's you can store them in a containing div "row" that has a variable height.
Sorry of that doesn't make much sense but try this CSS on the row's div.
min-height: 100px; /*whatever you want the minimum height to be*/
height:auto !important; /*An IE fix for older versions */
height:100%;
The above css will ensure your div is never smaller than 100px but can grow based on its content.
The solution is quite simple:
#container>div {
width:25%;
margin:0;
border:0;
float:left;
}
#container>div.farleft {
clear:both;
}
jsfiddle

Making child element disappear on it's parent's `mouseleave`

I have a red div with green child, the green one moves when mouse hovers over it's parent. Pretty simple.
HTML:
<div class="big">
<div class="small"></div>
</div>
CSS:
.big {
position: relative;
width: 200px; height: 200px;
margin: 20px auto;
background: red;
}
.big:hover .small {
opacity: 1;
}
.small {
position: absolute;
top: 0; left: 0;
width: 50px; height: 50px;
background: green;
opacity: 0;
}
JavaScript:
$('.big').on('mousemove', function (e) {
var $this = $(this),
small = $this.find('.small'),
offset = $this.offset(),
cursorX = e.pageX - offset.left,
cursorY = e.pageY - offset.top,
smallX = cursorX - small.width() / 2,
smallY = cursorY - small.height() / 2;
$('.small').css({
top: smallY,
left: smallX
});
});
How to make the green box to disappear when it leaves the red one? :hover in css doesn't work because green div is part of the red one (I quess), so cursor never actually leaves it. Only when you move themouse really quickly the green div can't keep up with the cursor and disappers. Perhaps adding some wrapper elements with specific positioning will do the trick? Or something like jQuery stopPropagation()?
Here's my Fiddle
UPDATE: Here's updated code, based on suggestions from user nevermind. I added a transition, it disappears as I wanted it to, but now there's other problem. When cursor is moved outside the red box quickly, the green box stays at the border of it's parent.
I think this is what you want:
http://jsbin.com/obewaz/1/
http://jsbin.com/obewaz/1/edit
Same html/css, few additions in jquery:
$(document).ready(function() {
$('.big').on('mousemove', function (e) {
var $this = $(this),
smalle = $this.find('.small'),
offset = $this.offset(),
position=smalle.position(),
cursorX = e.pageX - offset.left,
cursorY = e.pageY - offset.top,
smallX = cursorX - smalle.width() / 2,
smallY = cursorY - smalle.height() / 2;
$('.small').css({
top: smallY,
left: smallX
});
console.log(position);
if(position.left<0 || position.left>150 || position.top<0 || position.top>150) {
$('.small').css('display','none');
}
else {
$('.small').css('display','block');
}
});
});
Of course, you can change/tweak values in last condition a little to fit your needs. Idea is: track position of small box, and when it is 'outside' of big box - hide it.
instead of mousemove try mouseover
DEMO

Rendering a Div Based on Browser Type

I have a div tag that looks as follows:
<div id="loadingDiv" class="loadingDiv"; style="position:absolute; left:400px; top:292px;">
<strong>Retrieving Data - One Moment Please...</strong>
</div>
It seems that Chrome and IE do not render this the same way. In IE, the text is much further to the left than with Chrome. I don't know why this is. So, is there a way I can create a style that is dependent on the browser type? For example, if the browser is IE, I'd like the left value to be maybe 300px, and 400px if Chrome. Or, is there a better way to handle this?
Even if I don't recommend to use browser specific CSS, it is always much better to optimize your CSS to look at least simmilar in all browsers, you can do what you want by using of some javascript combined with CSS.
Here is the code:
<html>
<head>
<title>browser specific css</title>
<style>
.loadingDiv {
position: absolute;
display: none;
font-weight: bold;
}
.loadingDiv.ie {
display: block;
left: 300px;
top: 292px;
background: #00CCFF;
color: #454545;
}
.loadingDiv.chrome {
display: block;
left: 400px;
top: 292px;
background: #FCD209;
color: #E53731;
}
.loadingDiv.firefox {
display: block;
left: 400px;
top: 292px;
background: #D04F16;
color: #FFFFFF;
}
.loadingDiv.default {
display: block;
left: 400px;
top: 292px;
}
</style>
<script>
window.onload = function() {
var check_for_ie = detect_browser("MSIE");
var check_for_chrome = detect_browser("Chrome");
var check_for_firefox = detect_browser("Firefox");
var browser_name = "";
var loading_div = document.getElementById("loadingDiv");
var loading_div_html = loading_div.innerHTML;
if (check_for_ie == true) {
browser_name = "Internet Explorer";
loading_div.className = "loadingDiv ie";
}
else if (check_for_chrome == true) {
browser_name = "Google Chrome";
loading_div.setAttribute("class","loadingDiv chrome");
}
else if (check_for_firefox == true) {
browser_name = "Firefox";
loading_div.setAttribute("class","loadingDiv firefox");
}
else {
browser_name = "Unchecked browser";
loading_div.setAttribute("class","loadingDiv default");
}
loading_div.innerHTML = loading_div_html + "(you are browsing with "+browser_name+")";
}
function detect_browser(look_for) {
var user_agent_string = navigator.userAgent;
var search_for_string = user_agent_string.search(look_for);
if (search_for_string > -1) {
return true;
}
else {
return false;
}
}
</script>
</head>
<body>
<div id="loadingDiv" class="loadingDiv" >
Retrieving Data - One Moment Please...
</div>
</body>
</html>
And here is the working example:
http://simplestudio.rs/yard/browser_specific_css/browser_specific_css.html
EDIT:
If you need to check for some other browsers look at user agent string of that specific browser and find something that is unique in it and makes a difference between that browser and the others and use that like this:
var check_for_opera = detect_browser("Opera");
Detecting browsers by user agent could be tricky so be careful, even upgrade my function if you need...
NOTE, that this is just quick example...

Margin, position and padding not working when display:inline is set. also weird behaviour from relative position

I have two CSS classes:
.class1 {
height: 100%;
width: 300px;
border: 1px none #B0B0B0;
position: relative;
display: inline;
left: 10px;
}
.class2 {
height: 100%;
width: 200px;
position: relative;
display: inline;
margin-left: 15px;
background-color: #00CCCC;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
}
Now, as you can see, they're both set to display in a line (no line breaks in between elements). Which works correctly. But for some reason, ever since I set the display to inline, the Padding, the Positioning and the Margin CSS have all just stopped working. I can add a margin-left 10inches and nothing will happen. Same with padding and positioning.
Can anyone explain how to fix this?
Also, I have the relative position set on both classes, yet when viewing the page in a browser, .class2 over laps .class1 when its supposed to be just after .class1.
Any ideas?
EDIT:
Okay, so I've done a JSFiddle, but it seems to be playing up even more there....
Looks like the Width is not working....
here it is:
http://jsfiddle.net/zYbwh/1/
You need to use
display: inline-block;
instead. margin doesn't work with display: inline elements, however with inline-block it does. You can then have an inline element with margins and explicit widths/heights.
To make this work in IE7, add these two lines:
*display: inline;
zoom: 1;
It's horrible, but it works.
I know this is quite a late answer but I wrote a jQuery plugin which support padding on inline elements (with word breaking) see this JSfiddle:
http://jsfiddle.net/RxKek/
Plugin Code:
$.fn.outerHTML = function () {
// IE, Chrome & Safari will comply with the non-standard outerHTML, all others (FF) will have a fall-back for cloning
return (!this.length) ? this : (this[0].outerHTML || (
function (el) {
var div = document.createElement('div');
div.appendChild(el.cloneNode(true));
var contents = div.innerHTML;
div = null;
return contents;
})(this[0]));
};
/*
Requirements:
1. The container must NOT have a width!
2. The element needs to be formatted like this:
<div>text</div>
in stead of this:
<div>
text
</div>
*/
$.fn.fixInlineText = function (opt) {
return this.each(function () {
//First get the container width
var maxWidth = opt.width;
//Then get the width of the inline element
//To calculate the correct width the element needs to
//be 100% visible that's why we make it absolute first.
//We also do this to the container.
$(this).css("position", "absolute");
$(this).parent().css("position", "absolute").css("width", "200%");
var width = $(this).width();
$(this).css("position", "");
$(this).parent().css("position", "").css("width", "");
//Don't do anything if it fits
if (width < maxWidth) {
return;
}
//Check how many times the container fits within the box
var times = Math.ceil(width / maxWidth);
//Function for cleaning chunks
var cleanChunk = function (chunk) {
var thisChunkLength = chunk.length - 1;
if (chunk[0] == " ") chunk = chunk.substring(1);
if (chunk[thisChunkLength] == " ") chunk = chunk.substring(0, thisChunkLength);
return chunk;
};
//Divide the text into chunks
var text = $(this).html();
var textArr = text.split(" ");
var chunkLength = Math.ceil((textArr.length - 1) / times);
var chunks = [];
var curChunk = "";
var curChunkCount = 0;
var isParsingHtml = false;
//Loop through the text array and split it into chunks
for (var i in textArr) {
//When we are parsing HTML we don't want to count the
//spaces since the user doesn't see it.
if (isParsingHtml) {
//Check for a HTML end tag
if (/<\/[a-zA-Z]*>/.test(textArr[i]) || /[a-zA-Z]*>/.test(textArr[i])) {
isParsingHtml = false;
}
} else {
//Check for a HTML begin tag
if (/<[a-zA-Z]*/.test(textArr[i])) {
isParsingHtml = true;
}
}
//Calculate chunks
if (curChunkCount == (chunkLength - 1) && !isParsingHtml) {
curChunk += textArr[i] + " ";
chunks.push(cleanChunk(curChunk));
curChunk = "";
curChunkCount = -1;
} else if ((i == (textArr.length - 1))) {
curChunk += textArr[i];
chunks.push(cleanChunk(curChunk));
break;
} else {
curChunk += textArr[i] + " ";
}
if (!isParsingHtml) {
curChunkCount++;
}
}
//Convert chunks to new elements
var el = $($(this).html("").outerHTML());
for (var x in chunks) {
var new_el = el.clone().html(chunks[x]).addClass("text-render-el");
var new_el_container = $("<div/>").addClass("text-render-container");
new_el_container.append(new_el);
$(this).before(new_el_container);
}
//Finally remove the current element
$(this).remove();
});
};
Thats the problem you get when using templates, ive programmed a site in php, but the design is killing me.
So i try'd some rocket fuel for webdesigners.
And this is the problems i keep getting every step of the way...
Inline-block does not work for me, nothing works, becouse it is not my design and i dont know the setup.
Ive tryd doing the design myself, but i am out of time, i need a design yesterday.
I suggest you take what u need from the templates and delete everything else, that will schrink your problem, and save you time.

Resources