I'm looking for some help, I'm trying to recreate the homepage on this site.
https://madebyarticle.com/
I don't want to use Jquery, either Plain JS or Vue.
I've got it to do most what I want it to but have a few issues.
Codepen Example
HTML
<main id="parent" class="Loop js-loop">
<section>
<h1 class="step1">One</h1>
</section>
<section>
<h1 class="step2">For</h1>
</section>
<section>
<h1 class="step3">All</h1>
</section>
<section>
<h1>And</h1>
</section>
<section>
<h1>All</h1>
</section>
<section>
<h1>For</h1>
</section>
<!--
These blocks are the same as the first blocks to get that looping illusion going.
You need to add clones to fill out a full viewport height.
-->
<section class="green is-clone">
<h1>One</h1>
</section>
<section class="red is-clone">
<h1>For</h1>
</section>
</main>
CSS
html,
body {
height: 100%;
overflow: hidden;
}
.Loop {
position: relative;
height: 100%;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
section {
position: relative;
text-align: center;
/* min-height: 300px;
max-height: 700px; */
height: 100vh;
}
::scrollbar {
display: none;
}
body {
font-family: "Avenir Next", Helvetica, sans-serif;
font-weight: normal;
font-size: 100%;
}
h1 {
margin: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
font-size: 80px;
letter-spacing: 5px;
/* color: #fff; */
text-transform: uppercase;
}
.mystyle {
background: red;
}
.mystyle1 {
background-image: url(https://images.unsplash.com/photo-1528834379234-2de7f8328fd8?ixlib=rb-1.2.1&auto=format&fit=crop&w=1920&q=10);
}
.mystyle2 {
background-image: url(https://images.unsplash.com/photo-1501854140801-50d01698950b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2600&q=80);
}
JS
var doc = window.document,
context = doc.querySelector(".js-loop"),
clones = context.querySelectorAll(".is-clone"),
disableScroll = false,
scrollHeight = 0,
scrollPos = 0,
clonesHeight = 0,
i = 0;
function getScrollPos() {
return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}
function setScrollPos(pos) {
context.scrollTop = pos;
}
function getClonesHeight() {
clonesHeight = 0;
for (i = 0; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
function reCalc() {
scrollPos = getScrollPos();
scrollHeight = context.scrollHeight;
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
}
}
function scrollUpdate() {
if (!disableScroll) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= scrollHeight) {
// Scroll to the top when you’ve reached the bottom
setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the bottom when you reach the top
setScrollPos(scrollHeight - clonesHeight);
disableScroll = true;
}
}
if (disableScroll) {
// Disable scroll-jumping for a short time to avoid flickering
window.setTimeout(function() {
disableScroll = false;
}, 40);
}
}
function init() {
reCalc();
context.addEventListener(
"scroll",
function() {
window.requestAnimationFrame(scrollUpdate);
},
false
);
window.addEventListener(
"resize",
function() {
window.requestAnimationFrame(reCalc);
},
false
);
}
if (document.readyState !== "loading") {
init();
} else {
doc.addEventListener("DOMContentLoaded", init, false);
}
// Just for this demo: Center the middle block on page load
window.onload = function() {
setScrollPos(
Math.round(
clones[0].getBoundingClientRect().top +
getScrollPos() -
(context.offsetHeight - clones[0].offsetHeight) / 2
)
);
};
const images = document.querySelectorAll('h1');
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
entry.target.classList.add('active');
} else {
entry.target.classList.remove('active');
}
});
});
images.forEach(image => {
observer.observe(image);
});
const header = document.getElementById("parent");
const sectionOne = document.querySelector("h1.step1");
const sectionTwo = document.querySelector("h1.step2");
const sectionThree = document.querySelector("h1.step3");
const sectionOneObserver = new IntersectionObserver(function(
entries,
sectionOneObserver
) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
header.classList.add("mystyle");
} else {
header.classList.remove("mystyle");
}
});
});
sectionOneObserver.observe(sectionOne);
const sectionTwoObserver = new IntersectionObserver(function(
entries,
sectionTwoObserver
) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
header.classList.add("mystyle1");
} else {
header.classList.remove("mystyle1");
}
});
});
sectionTwoObserver.observe(sectionTwo);
const sectionThreeObserver = new IntersectionObserver(function(
entries,
sectionThreeObserver
) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
header.classList.add("mystyle2");
} else {
header.classList.remove("mystyle2");
}
});
});
sectionThreeObserver.observe(sectionThree);
// if (document.querySelectorAll('h1.step1.active')){
// document.getElementById("parent").classList.toggle("mystyle");
// } else {
// document.getElementById("parent").classList.remove("mystyle");
// }
// if (document.classList.contains("h1.step1.active")) {
// document.getElementById("parent").classList.add("mystyle");
// } else {
// document.getElementById("parent").classList.remove("mystyle");
// }
I'm having to duplicate the IntersectionObserver for every image I need, is there a cleaner way todo this?
At some points, there are 2 active states so it doesn't display any image only a background colour.
What would be the best way to fade the image on change like the example website?
Are there any examples or scripts that can do what I'm trying todo?
Thanks
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I am trying to create toast notifications, for the most part, my code is working fine enough. However, I am struggling to position my toasts on top of everything else in the page, so that toast #1 appears on top of everything in the top of the page, toast #2 appears on top of everything, but will be stacked under toast #1, etc.
Here is my code:
$(document).ready(function() {
$("#btnSuccess").click(function() {
createSuccessToast("everything is fine");
});
$("#btnError").click(function() {
createErrorToast("something went wrong");
});
});
function createSuccessToast(toastMessage) {
createToast(true, toastMessage);
}
function createErrorToast(toastMessage) {
createToast(false, toastMessage);
}
function createToast(isSuccess, toastMessage) {
var toastContainer = createToastContainer(isSuccess);
createToastHeader(toastContainer, isSuccess);
createToastContent(toastContainer, toastMessage);
initToast(toastContainer);
destroyToast(toastContainer);
}
function createToastContainer(isSuccess) {
var toastContainer = $("<div></div>");
toastContainer.addClass("toastContainer");
if (isSuccess) {
toastContainer.addClass("toastContainerSuccess");
} else {
toastContainer.addClass("toastContainerError");
}
return toastContainer;
}
function createToastHeader(toastContainer, isSuccess) {
var toastHeader = $("<div></div>");
toastHeader.addClass("toastHeader");
toastHeader.html(isSuccess ? "Success" : "Error");
toastContainer.append(toastHeader);
}
function createToastContent(toastContainer, toastMessage) {
var toastContent = $("<div></div>");
toastContent.addClass("toastContent");
toastContent.html(toastMessage);
toastContainer.append(toastContent);
}
function initToast(toastContainer) {
toastContainer.hide(function() {
$(document.body).append(toastContainer);
toastContainer.fadeIn(500);
});
}
function destroyToast(toastContainer) {
setTimeout(function() {
toastContainer.fadeOut(500, function() {
toastContainer.remove();
});
}, 5000);
}
.toastContainer {
margin-top: 10px;
border-radius: 5px;
font-weight: bold;
padding: 10px;
color: #ffffff;
}
.toastContainerSuccess {
background-color: #99ff33;
}
.toastContainerError {
background-color: #ff1a1a;
}
.toastHeader {}
.toastContent {
margin-top: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnSuccess">
Success
</button>
<button id="btnError">
Error
</button>
To achieve my desired results, I added 2 CSS properties to .toastContainer:
position: absolute;
z-index: 1;
But then, all toasts would spawn at the exact same location on the page, so if there were multiple toasts, only the most recent would be visible.
You should append the toasts to a container element which is position: absolute; z-index: 1 instead (because if multiple elements are position: absolute, and they have the same top/left positions, they WILL appear on top of another, see this):
$(document).ready(function() {
$("#btnSuccess").click(function() {
createSuccessToast("everything is fine");
});
$("#btnError").click(function() {
createErrorToast("something went wrong");
});
});
function createSuccessToast(toastMessage) {
createToast(true, toastMessage);
}
function createErrorToast(toastMessage) {
createToast(false, toastMessage);
}
function createToast(isSuccess, toastMessage) {
var toastContainer = createToastContainer(isSuccess);
createToastHeader(toastContainer, isSuccess);
createToastContent(toastContainer, toastMessage);
initToast(toastContainer);
destroyToast(toastContainer);
}
function createToastContainer(isSuccess) {
var toastContainer = $("<div></div>");
toastContainer.addClass("toastContainer");
if (isSuccess) {
toastContainer.addClass("toastContainerSuccess");
} else {
toastContainer.addClass("toastContainerError");
}
return toastContainer;
}
function createToastHeader(toastContainer, isSuccess) {
var toastHeader = $("<div></div>");
toastHeader.addClass("toastHeader");
toastHeader.html(isSuccess ? "Success" : "Error");
toastContainer.append(toastHeader);
}
function createToastContent(toastContainer, toastMessage) {
var toastContent = $("<div></div>");
toastContent.addClass("toastContent");
toastContent.html(toastMessage);
toastContainer.append(toastContent);
}
function initToast(toastContainer) {
toastContainer.hide(function() {
$("#toastsContainer").append(toastContainer);
toastContainer.fadeIn(500);
});
}
function destroyToast(toastContainer) {
setTimeout(function() {
toastContainer.fadeOut(500, function() {
toastContainer.remove();
});
}, 5000);
}
#toastsContainer {
position: absolute;
top: 0;
z-index: 1;
width: 100%;
}
.toastContainer {
margin-top: 10px;
border-radius: 5px;
font-weight: bold;
padding: 10px;
color: #ffffff;
position: relative;
z-index: 1;
}
.toastContainerSuccess {
background-color: #99ff33;
}
.toastContainerError {
background-color: #ff1a1a;
}
.toastHeader {}
.toastContent {
margin-top: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnSuccess">
Success
</button>
<button id="btnError">
Error
</button>
<div id="toastsContainer"></div>
Please try the below code, I have used the global variable pos, and accordingly set the position of the buttons dynamically after the button click, and after the fade out the buttons will move back to the previous position again.
var pos = 80;
$(document).ready(function() {
$("#btnSuccess").click(function() {
document.getElementById("btnSuccess").style.top= ""+pos+"px";
document.getElementById("btnError").style.top= ""+pos+"px";
pos = pos + 80;
createSuccessToast("everything is fine");
});
$("#btnError").click(function() {
document.getElementById("btnSuccess").style.top= ""+pos+"px";
document.getElementById("btnError").style.top= ""+pos+"px";
pos = pos + 80;
createErrorToast("something went wrong");
});
});
function createSuccessToast(toastMessage) {
createToast(true, toastMessage);
}
function createErrorToast(toastMessage) {
createToast(false, toastMessage);
}
function createToast(isSuccess, toastMessage) {
var toastContainer = createToastContainer(isSuccess);
createToastHeader(toastContainer, isSuccess);
createToastContent(toastContainer, toastMessage);
initToast(toastContainer);
destroyToast(toastContainer);
}
function createToastContainer(isSuccess) {
var toastContainer = $("<div></div>");
toastContainer.addClass("toastContainer");
if (isSuccess) {
toastContainer.addClass("toastContainerSuccess");
} else {
toastContainer.addClass("toastContainerError");
}
return toastContainer;
}
function createToastHeader(toastContainer, isSuccess) {
var toastHeader = $("<div></div>");
toastHeader.addClass("toastHeader");
toastHeader.html(isSuccess ? "Success" : "Error");
toastContainer.append(toastHeader);
}
function createToastContent(toastContainer, toastMessage) {
var toastContent = $("<div></div>");
toastContent.addClass("toastContent");
toastContent.html(toastMessage);
toastContainer.append(toastContent);
}
function initToast(toastContainer) {
toastContainer.hide(function() {
$(document.body).append(toastContainer);
toastContainer.fadeIn(500);
});
}
function destroyToast(toastContainer) {
setTimeout(function() {
pos = pos - 160;
toastContainer.fadeOut(500, function() {
document.getElementById("btnSuccess").style.top= ""+pos+"px";
document.getElementById("btnError").style.top= ""+pos+"px";
toastContainer.remove();
pos = pos + 80;
});
}, 5000);
}
.toastContainer {
bottom:20px;
position:relative;
z-index:1;
margin-top: 10px;
border-radius: 5px;
font-weight: bold;
padding: 10px;
color: #ffffff;
}
#btnSuccess{
position:relative;
}
#btnError{
position:relative;
}
.toastContainerSuccess {
background-color: #99ff33;
}
.toastContainerError {
background-color: #ff1a1a;
}
.toastHeader {}
.toastContent {
margin-top: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnSuccess">
Success
</button>
<button id="btnError">
Error
</button>
I have two divs that are overlapping using Bootstrap's 2.3.2 grid system when the browser is resized. The result looks like the following after you downsize the browser window:
I don't want the two divs to ever overlap. If it comes to a point where they cannot fit on the same row, the second div should fall below the first, which the responsive layout is already doing. My problem is those weird few pixels where they overlap.
I'm using Bootstrap's tags input library here.
The HTML:
<div class="container-fluid">
<div class="row-fluid">
<div class="span12" style="border: 1px solid black;">
<div class="span1 offset4" style="border: 1px solid blue;">
<select id="container" multiple data-role="tagsinput"> </select>
</div>
<div class="span2 offset2" style="border: 1px solid red;">
<h4>
Second Div
</h4>
<div id="second_div">
<p>
testing...... 1 ... 2 ... 3...
</p>
</div>
</div>
</div>
</div>
</div>
JavaScript to populate some dummy data:
$(document).ready(function() {
$('select').tagsinput('add', 'Foo');
$('select').tagsinput('add', 'Bar');
$('select').tagsinput('add', 'This is a very very very very very very long filter');
});
And my CSS:
.small {
font-size: 10px;
}
.tag {
/*height: 25px;*/
vertical-align: middle;
line-height: 25px;
/*width: 75%;*/
word-wrap: break-word;
white-space: normal;
}
ul {
list-style-type: none;
}
.top-margin {
margin-top: 5px;
}
.bootstrap-tagsinput {
width: 200px;
max-width: none;
}
I have a jsfiddle which demos the problem here: https://jsfiddle.net/brseyg6c/
The problem is not Bootstrap but instead this declaration:
.bootstrap-tagsinput {
width: 200px;
max-width: none;
}
You're fixing the width of the tag container while it's inside a dynamically sized Bootstrap column.
Instead, have the container fill the width of the column:
.bootstrap-tagsinput {
box-sizing: border-box;
width: 100%;
}
You might want to increase the width of the left column (change span1 to be larger) and remove the offset from the right column.
I have two idea for you.
Trick 1: Can you make it like this with out media query just replace the off-set2 and make offset3. and add this into class .bootstrap-tagsinput .tag white-space:pre-wrap; .otherwise in snippet large tag came out of the box. Trick 2 Fiddle
.bootstrap-tagsinput {
background-color: #fff;
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
display: inline-block;
padding: 4px 6px;
color: #555;
vertical-align: middle;
border-radius: 4px;
max-width: 100%;
line-height: 22px;
cursor: text;
}
.bootstrap-tagsinput input {
border: none;
box-shadow: none;
outline: none;
background-color: transparent;
padding: 0 6px;
margin: 0;
width: auto;
max-width: inherit;
}
.bootstrap-tagsinput.form-control input::-moz-placeholder {
color: #777;
opacity: 1;
}
.bootstrap-tagsinput.form-control input:-ms-input-placeholder {
color: #777;
}
.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {
color: #777;
}
.bootstrap-tagsinput input:focus {
border: none;
box-shadow: none;
}
.bootstrap-tagsinput .tag {
margin-top: 5px;
/* custom */
margin-right: 2px;
color: white;
white-space:pre-wrap;
}
.bootstrap-tagsinput .tag [data-role="remove"] {
margin-left: 8px;
cursor: pointer;
}
.bootstrap-tagsinput .tag [data-role="remove"]:after {
content: "x";
padding: 0px 2px;
}
.bootstrap-tagsinput .tag [data-role="remove"]:hover {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
body {
padding: 20px;
}
h1, h2, h3, h4, h5, h6 {
text-shadow: 1px 1px 1px #fff;
color: #000;
font-weight: bold;
line-height: 1.5;
margin: 0;
}
pre {
border-radius: 3px;
overflow-x: scroll;
}
p {
color: #000;
}
p a {
color: #990033;
text-decoration: none;
transition: all .25s;
padding: 3px;
}
p a:hover {
color: #fff;
background: #990033;
transition: all .25s;
}
ul,
ol {
margin-top: -10px;
}
.white {
color: white;
}
.small {
font-size: 10px;
}
.tag {
/*height: 25px;*/
vertical-align: middle;
line-height: 25px;
/*width: 75%;*/
word-wrap: break-word;
white-space: normal;
}
ul {
list-style-type: none;
}
.top-margin {
margin-top: 5px;
}
.bootstrap-tagsinput {
width: 200px;
max-width: none;
}
<head>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" ></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/js/bootstrap.min.js" ></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css" />
<link href="https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12" style="border: 1px solid black;">
<div class="span1 offset4" style="border: 1px solid blue;">
<select id="container" multiple data-role="tagsinput"> </select>
</div>
<div class="span2 offset3" style="border: 1px solid red;">
<h4>
Second Div
</h4>
<div id="event-log">
<p>
testing...... 1 ... 2 ... 3...
</p>
</div>
</div>
</div>
</div>
</div>
</body>
(function($) {
"use strict";
var defaultOptions = {
tagClass: function(item) {
return 'label label-info';
},
itemValue: function(item) {
return item ? item.toString() : item;
},
itemText: function(item) {
return this.itemValue(item);
},
itemTitle: function(item) {
return null;
},
freeInput: true,
addOnBlur: true,
maxTags: undefined,
maxChars: undefined,
confirmKeys: [13, 44],
delimiter: ',',
delimiterRegex: null,
cancelConfirmKeysOnEmpty: true,
onTagExists: function(item, $tag) {
$tag.hide().fadeIn();
},
trimValue: false,
allowDuplicates: false
};
/**
* Constructor function
*/
function TagsInput(element, options) {
this.itemsArray = [];
this.$element = $(element);
this.$element.hide();
this.isSelect = (element.tagName === 'SELECT');
this.multiple = (this.isSelect && element.hasAttribute('multiple'));
this.objectItems = options && options.itemValue;
this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
this.inputSize = Math.max(1, this.placeholderText.length);
this.$container = $('<div class="bootstrap-tagsinput"></div>');
this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
this.$element.before(this.$container);
this.build(options);
}
TagsInput.prototype = {
constructor: TagsInput,
/**
* Adds the given item as a new tag. Pass true to dontPushVal to prevent
* updating the elements val()
*/
add: function(item, dontPushVal, options) {
var self = this;
if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
return;
// Ignore falsey values, except false
if (item !== false && !item)
return;
// Trim value
if (typeof item === "string" && self.options.trimValue) {
item = $.trim(item);
}
// Throw an error when trying to add an object while the itemValue option was not set
if (typeof item === "object" && !self.objectItems)
throw ("Can't add objects when itemValue option is not set");
// Ignore strings only containg whitespace
if (item.toString().match(/^\s*$/))
return;
// If SELECT but not multiple, remove current tag
if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
self.remove(self.itemsArray[0]);
if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
var items = item.split(delimiter);
if (items.length > 1) {
for (var i = 0; i < items.length; i++) {
this.add(items[i], true);
}
if (!dontPushVal)
self.pushVal();
return;
}
}
var itemValue = self.options.itemValue(item),
itemText = self.options.itemText(item),
tagClass = self.options.tagClass(item),
itemTitle = self.options.itemTitle(item);
// Ignore items allready added
var existing = $.grep(self.itemsArray, function(item) {
return self.options.itemValue(item) === itemValue;
})[0];
if (existing && !self.options.allowDuplicates) {
// Invoke onTagExists
if (self.options.onTagExists) {
var $existingTag = $(".tag", self.$container).filter(function() {
return $(this).data("item") === existing;
});
self.options.onTagExists(item, $existingTag);
}
return;
}
// if length greater than limit
if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
return;
// raise beforeItemAdd arg
var beforeItemAddEvent = $.Event('beforeItemAdd', {
item: item,
cancel: false,
options: options
});
self.$element.trigger(beforeItemAddEvent);
if (beforeItemAddEvent.cancel)
return;
// register item in internal array and map
self.itemsArray.push(item);
// add a tag element
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
$tag.data('item', item);
self.findInputWrapper().before($tag);
$tag.after(' ');
// add <option /> if item represents a value not present in one of the <select />'s options
if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element)[0]) {
var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
$option.data('item', item);
$option.attr('value', itemValue);
self.$element.append($option);
}
if (!dontPushVal)
self.pushVal();
// Add class when reached maxTags
if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
self.$container.addClass('bootstrap-tagsinput-max');
self.$element.trigger($.Event('itemAdded', {
item: item,
options: options
}));
},
/**
* Removes the given item. Pass true to dontPushVal to prevent updating the
* elements val()
*/
remove: function(item, dontPushVal, options) {
var self = this;
if (self.objectItems) {
if (typeof item === "object")
item = $.grep(self.itemsArray, function(other) {
return self.options.itemValue(other) == self.options.itemValue(item);
});
else
item = $.grep(self.itemsArray, function(other) {
return self.options.itemValue(other) == item;
});
item = item[item.length - 1];
}
if (item) {
var beforeItemRemoveEvent = $.Event('beforeItemRemove', {
item: item,
cancel: false,
options: options
});
self.$element.trigger(beforeItemRemoveEvent);
if (beforeItemRemoveEvent.cancel)
return;
$('.tag', self.$container).filter(function() {
return $(this).data('item') === item;
}).remove();
$('option', self.$element).filter(function() {
return $(this).data('item') === item;
}).remove();
if ($.inArray(item, self.itemsArray) !== -1)
self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
}
if (!dontPushVal)
self.pushVal();
// Remove class when reached maxTags
if (self.options.maxTags > self.itemsArray.length)
self.$container.removeClass('bootstrap-tagsinput-max');
self.$element.trigger($.Event('itemRemoved', {
item: item,
options: options
}));
},
/**
* Removes all items
*/
removeAll: function() {
var self = this;
$('.tag', self.$container).remove();
$('option', self.$element).remove();
while (self.itemsArray.length > 0)
self.itemsArray.pop();
self.pushVal();
},
/**
* Refreshes the tags so they match the text/value of their corresponding
* item.
*/
refresh: function() {
var self = this;
$('.tag', self.$container).each(function() {
var $tag = $(this),
item = $tag.data('item'),
itemValue = self.options.itemValue(item),
itemText = self.options.itemText(item),
tagClass = self.options.tagClass(item);
// Update tag's class and inner text
$tag.attr('class', null);
$tag.addClass('tag ' + htmlEncode(tagClass));
$tag.contents().filter(function() {
return this.nodeType == 3;
})[0].nodeValue = htmlEncode(itemText);
if (self.isSelect) {
var option = $('option', self.$element).filter(function() {
return $(this).data('item') === item;
});
option.attr('value', itemValue);
}
});
},
/**
* Returns the items added as tags
*/
items: function() {
return this.itemsArray;
},
/**
* Assembly value by retrieving the value of each item, and set it on the
* element.
*/
pushVal: function() {
var self = this,
val = $.map(self.items(), function(item) {
return self.options.itemValue(item).toString();
});
self.$element.val(val, true).trigger('change');
},
/**
* Initializes the tags input behaviour on the element
*/
build: function(options) {
var self = this;
self.options = $.extend({}, defaultOptions, options);
// When itemValue is set, freeInput should always be false
if (self.objectItems)
self.options.freeInput = false;
makeOptionItemFunction(self.options, 'itemValue');
makeOptionItemFunction(self.options, 'itemText');
makeOptionFunction(self.options, 'tagClass');
// Typeahead Bootstrap version 2.3.2
if (self.options.typeahead) {
var typeahead = self.options.typeahead || {};
makeOptionFunction(typeahead, 'source');
self.$input.typeahead($.extend({}, typeahead, {
source: function(query, process) {
function processItems(items) {
var texts = [];
for (var i = 0; i < items.length; i++) {
var text = self.options.itemText(items[i]);
map[text] = items[i];
texts.push(text);
}
process(texts);
}
this.map = {};
var map = this.map,
data = typeahead.source(query);
if ($.isFunction(data.success)) {
// support for Angular callbacks
data.success(processItems);
} else if ($.isFunction(data.then)) {
// support for Angular promises
data.then(processItems);
} else {
// support for functions and jquery promises
$.when(data)
.then(processItems);
}
},
updater: function(text) {
self.add(this.map[text]);
return this.map[text];
},
matcher: function(text) {
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
},
sorter: function(texts) {
return texts.sort();
},
highlighter: function(text) {
var regex = new RegExp('(' + this.query + ')', 'gi');
return text.replace(regex, "<strong>$1</strong>");
}
}));
}
// typeahead.js
if (self.options.typeaheadjs) {
var typeaheadConfig = null;
var typeaheadDatasets = {};
// Determine if main configurations were passed or simply a dataset
var typeaheadjs = self.options.typeaheadjs;
if ($.isArray(typeaheadjs)) {
typeaheadConfig = typeaheadjs[0];
typeaheadDatasets = typeaheadjs[1];
} else {
typeaheadDatasets = typeaheadjs;
}
self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function(obj, datum) {
if (typeaheadDatasets.valueKey)
self.add(datum[typeaheadDatasets.valueKey]);
else
self.add(datum);
self.$input.typeahead('val', '');
}, self));
}
self.$container.on('click', $.proxy(function(event) {
if (!self.$element.attr('disabled')) {
self.$input.removeAttr('disabled');
}
self.$input.focus();
}, self));
if (self.options.addOnBlur && self.options.freeInput) {
self.$input.on('focusout', $.proxy(function(event) {
// HACK: only process on focusout when no typeahead opened, to
// avoid adding the typeahead text as tag
if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
self.add(self.$input.val());
self.$input.val('');
}
}, self));
}
self.$container.on('keydown', 'input', $.proxy(function(event) {
var $input = $(event.target),
$inputWrapper = self.findInputWrapper();
if (self.$element.attr('disabled')) {
self.$input.attr('disabled', 'disabled');
return;
}
switch (event.which) {
// BACKSPACE
case 8:
if (doGetCaretPosition($input[0]) === 0) {
var prev = $inputWrapper.prev();
if (prev.length) {
self.remove(prev.data('item'));
}
}
break;
// DELETE
case 46:
if (doGetCaretPosition($input[0]) === 0) {
var next = $inputWrapper.next();
if (next.length) {
self.remove(next.data('item'));
}
}
break;
// LEFT ARROW
case 37:
// Try to move the input before the previous tag
var $prevTag = $inputWrapper.prev();
if ($input.val().length === 0 && $prevTag[0]) {
$prevTag.before($inputWrapper);
$input.focus();
}
break;
// RIGHT ARROW
case 39:
// Try to move the input after the next tag
var $nextTag = $inputWrapper.next();
if ($input.val().length === 0 && $nextTag[0]) {
$nextTag.after($inputWrapper);
$input.focus();
}
break;
default:
// ignore
}
// Reset internal input's size
var textLength = $input.val().length,
wordSpace = Math.ceil(textLength / 5),
size = textLength + wordSpace + 1;
$input.attr('size', Math.max(this.inputSize, $input.val().length));
}, self));
self.$container.on('keypress', 'input', $.proxy(function(event) {
var $input = $(event.target);
if (self.$element.attr('disabled')) {
self.$input.attr('disabled', 'disabled');
return;
}
var text = $input.val(),
maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
// Only attempt to add a tag if there is data in the field
if (text.length !== 0) {
self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
$input.val('');
}
// If the field is empty, let the event triggered fire as usual
if (self.options.cancelConfirmKeysOnEmpty === false) {
event.preventDefault();
}
}
// Reset internal input's size
var textLength = $input.val().length,
wordSpace = Math.ceil(textLength / 5),
size = textLength + wordSpace + 1;
$input.attr('size', Math.max(this.inputSize, $input.val().length));
}, self));
// Remove icon clicked
self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
if (self.$element.attr('disabled')) {
return;
}
self.remove($(event.target).closest('.tag').data('item'));
}, self));
// Only add existing value as tags when using strings as tags
if (self.options.itemValue === defaultOptions.itemValue) {
if (self.$element[0].tagName === 'INPUT') {
self.add(self.$element.val());
} else {
$('option', self.$element).each(function() {
self.add($(this).attr('value'), true);
});
}
}
},
/**
* Removes all tagsinput behaviour and unregsiter all event handlers
*/
destroy: function() {
var self = this;
// Unbind events
self.$container.off('keypress', 'input');
self.$container.off('click', '[role=remove]');
self.$container.remove();
self.$element.removeData('tagsinput');
self.$element.show();
},
/**
* Sets focus on the tagsinput
*/
focus: function() {
this.$input.focus();
},
/**
* Returns the internal input element
*/
input: function() {
return this.$input;
},
/**
* Returns the element which is wrapped around the internal input. This
* is normally the $container, but typeahead.js moves the $input element.
*/
findInputWrapper: function() {
var elt = this.$input[0],
container = this.$container[0];
while (elt && elt.parentNode !== container)
elt = elt.parentNode;
return $(elt);
}
};
/**
* Register JQuery plugin
*/
$.fn.tagsinput = function(arg1, arg2, arg3) {
var results = [];
this.each(function() {
var tagsinput = $(this).data('tagsinput');
// Initialize a new tags input
if (!tagsinput) {
tagsinput = new TagsInput(this, arg1);
$(this).data('tagsinput', tagsinput);
results.push(tagsinput);
if (this.tagName === 'SELECT') {
$('option', $(this)).attr('selected', 'selected');
}
// Init tags from $(this).val()
$(this).val($(this).val());
} else if (!arg1 && !arg2) {
// tagsinput already exists
// no function, trying to init
results.push(tagsinput);
} else if (tagsinput[arg1] !== undefined) {
// Invoke function on existing tags input
if (tagsinput[arg1].length === 3 && arg3 !== undefined) {
var retVal = tagsinput[arg1](arg2, null, arg3);
} else {
var retVal = tagsinput[arg1](arg2);
}
if (retVal !== undefined)
results.push(retVal);
}
});
if (typeof arg1 == 'string') {
// Return the results from the invoked function calls
return results.length > 1 ? results : results[0];
} else {
return results;
}
};
$.fn.tagsinput.Constructor = TagsInput;
/**
* Most options support both a string or number as well as a function as
* option value. This function makes sure that the option with the given
* key in the given options is wrapped in a function
*/
function makeOptionItemFunction(options, key) {
if (typeof options[key] !== 'function') {
var propertyName = options[key];
options[key] = function(item) {
return item[propertyName];
};
}
}
function makeOptionFunction(options, key) {
if (typeof options[key] !== 'function') {
var value = options[key];
options[key] = function() {
return value;
};
}
}
/**
* HtmlEncodes the given value
*/
var htmlEncodeContainer = $('<div />');
function htmlEncode(value) {
if (value) {
return htmlEncodeContainer.text(value).html();
} else {
return '';
}
}
/**
* Returns the position of the caret in the given input field
* http://flightschool.acylt.com/devnotes/caret-position-woes/
*/
function doGetCaretPosition(oField) {
var iCaretPos = 0;
if (document.selection) {
oField.focus();
var oSel = document.selection.createRange();
oSel.moveStart('character', -oField.value.length);
iCaretPos = oSel.text.length;
} else if (oField.selectionStart || oField.selectionStart == '0') {
iCaretPos = oField.selectionStart;
}
return (iCaretPos);
}
/**
* Returns boolean indicates whether user has pressed an expected key combination.
* #param object keyPressEvent: JavaScript event object, refer
* http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
* #param object lookupList: expected key combinations, as in:
* [13, {which: 188, shiftKey: true}]
*/
function keyCombinationInList(keyPressEvent, lookupList) {
var found = false;
$.each(lookupList, function(index, keyCombination) {
if (typeof(keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
found = true;
return false;
}
if (keyPressEvent.which === keyCombination.which) {
var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
if (alt && shift && ctrl) {
found = true;
return false;
}
}
});
return found;
}
/**
* Initialize tagsinput behaviour on inputs and selects which have
* data-role=tagsinput
*/
$(function() {
$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
});
})(window.jQuery);
$(document).ready(function() {
$('select').tagsinput('add', 'Another Model');
$('select').tagsinput('add', 'TestCam7');
$('select').tagsinput('add', 'TestCam4');
$('select').tagsinput('add', 'Profanity');
$('select').tagsinput('add', 'An Anddress');
$('select').tagsinput('add', 'This is a very very very very very very long filter');
});
Trick's 2: Using this 2 media query only you can achieve the same output. Trick's 2 fiddle
#media (min-width: 1076px) and (min-width: 979px) {
.row-fluid .span2 {
margin-left: 15.5%;
}
}
#media (max-width: 979px) and (min-width: 768px) {
.row-fluid .span2 {
margin-left: 25.5%;
}
}
I'm creating input that shows different notes based on content. First, I tried using content attribute of CSS, but it only works for :before and :after selectors.
So, I created another div element, using :before on it to display the note text. Should I switch to using JavaScript to do this?
JS Fiddle
HTML:
<div class="link-input-container">
<input class="link-input" placeholder="Zalijepi link ovdje..." type="text" class="url_input" name="url_input">
</div>
<div class="link-note no-input">
<div class="link-note-content">
</div>
</div>
CSS:
.link-input-container {
position: relative;
display: inline-block;
}
.link-input-container::after {
display: block;
content: "";
width: 14px;
height: 14px;
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAACT0lEQVRIS8WVS2sTURTHf2N8JMG2iK/WUt+LWpSilFIV9BPoByh059qNghsxtRtBcevCreAHqJ9AQQ0hVIqvitpqk2mrzUOrJK2JuXKGudNk5s60m+DAZTJzz/n/zuOeiUWbL6vN+vxfgE3yUi+VJ1FZbmQTmoE4WjCp4HIYZDM2RoB27Dl/lsXnLzFBPJuxURYfPTbaSOYBgHbsPjfiVWbpRbpFoFmcchlVKuO30c4BwAJJ1T0yHCj7UjrjQNyoJnvGRqFUQhVL64GkMxyg0qJpymDcgtT+4aEA5Fsm67wTcVUsogpFz0b2FNzupTLe7BjWAweyb+hMABI70Y8qFGgsF7y979kpo7ixB9rLJulA9p4ejJzF5VfToeKRANnUkD2Dp4yQwvTrSPENAWIgTd99csAIKL55F2iq3zDyUyHi0tC17FRomUrvZyIhoQAtXrcXqNu2A1CmwQHKHz6GQowALV7L29RyeS/6n58+O7+7jh8LZCR7/hkw9sATz+WpzefWxWfnnIa6Tqmuo0eCkNm5zQ9a5+FDnsDKl68tp0Wfrigb7Rw5aB0H+/g1n+MvTPRRcaLXV45kKga3tI1piv0lEtgWYCuwbYbEzU6sGz9Q9wao3nf72xyQekvi2i6s6yuou/1U7wB1oObeG3Iumh1EfDuwE+gA4s+IX73A6kMg5sLFXpYcKFmNp8SvXGT1gStcBX6764/s+wESfQJIAjvcbES8GaCr5ABAKugsiX4NqAACkucWgC6ZZKKXLpuO3H9yvEzcjASkwXJv/5/+P/1hAyh9doPuAAAAAElFTkSuQmCC') no-repeat;
background-size: contain;
background-position: center;
position: absolute;
top: 50%;
right: -5px;
transform: translateY(-50%) translateX(100%);
}
.link-input-container.valid::after {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAACHklEQVRIS+2Vv27TQBzHv2fT4PhPUjEg0Y6deACmdiviBViZoM/A2padN6Bdu/EASNnIwBMwdQApiCFVqGM7dl370PfqS8+xm0RU3TjpJzun8+fzu9/v7Ag88BAPzMd/garw2y+7W8LGSBbYPn01/GWW/d4l0vCd5zs4/36ORcm9BCY8yzOkeYrxj3FN8s+CNrguDSUn+0PFbgiW1VMDTHh6larMhbhBES4gjj/tfz1qCFbV02woaz7LZkizFLCgBBc/L2rwmkDDN59tout04Tpuo2lmAsksQZImCiwsgclo0oDXBO8Gu5JwKSVkKeF2XXiuN5eoxTZGzDyOY8RJrMCMy9+XrfCa4GCwdyQhD3tPeyjLUkl8z4fv+0rCQXg0jTCNp/PMo3F0J7zRAy3xnnhKwAiCAEEvUIIwDDENb+HJn2QpvPUUaYnTc+aSfr8PCYlwEt401BLIomwlvFXASS3puB3IQqq+6MGm5lm+FvxOgSmxN2xAQkkIL66LteFLBaaEJZlLjJdonf+SVZ8KcTDYO+TpUjCJDycvh8cLYF2/2zoaC0wB7y0AjwBsVFebc28+v3hfSEucvf720XiWQEZZRQHgGkBeXTkvTQHhHQA+AJ5LpxJRokTVt4vPmHCCGQTPAERVXFG8KGD2XQAugMfGLkyB3oTOXguYfQYgqUT8XRPopjNTHbpsvLb1y9wJ7ynTYtWTVU1e56AsXfMXq50xKBJ0RMMAAAAASUVORK5CYII=')
}
.link-input {
font-family: Courier New;
font-size: 12px;
}
.link-input-container.valid .link-input {
color: green;
}
.link-input-container:not(valid) .link-input {
color: red;
}
.link-note {
font-size: 12px;
}
.link-note.no-input {
color: rgb(193, 162, 0);
}
.link-note.no-input .link-note-content:before {
content: "*Link nije unesen";
}
.link-note.valid {
color: green;
}
.link-note.valid .link-note-content:before {
content: "*Stisni enter da dodas ovaj link";
}
.link-note.invalid {
color: red;
}
.link-note.invalid .link-note-content:before {
content: "*Link nije ispravan";
}
JS:
function toggleClass(elem, class_name, class_on) {
if (class_on) {
elem.classList.add(class_name);
} else {
elem.classList.remove(class_name);
}
}
function switchClass(elem, class_list, on_class) {
for (var i = 0; i < class_list.length; i++) {
elem.classList.remove(class_list[i]);
}
elem.classList.add(on_class);
}
function LinkInput() {
LinkInput = null;
var self = {
container_elem: null,
input_elem: null,
note_elem: null,
init: () => {
var container_elem = self.container_elem = document.querySelector(
'.link-input-container'
);
var input_elem = self.input_elem = document.querySelector(
'.link-input'
);
input_elem.size = 23;
var note_elem = self.note_elem = document.querySelector(
'.link-note'
);
input_elem.addEventListener('input', (ev) => {
var new_val = input_elem.value;
var new_size = new_val.length;
input_elem.size = Math.max(new_size + 2, 23);
if (new_val.length > 5) {
switchClass(note_elem, [
"no-input", "invalid", "valid"
], "valid");
toggleClass(container_elem, "valid", true);
} else {
if (new_val === "") {
switchClass(note_elem, [
"no-input", "invalid", "valid"
], "no-input");
} else {
switchClass(note_elem, [
"no-input", "invalid", "valid"
], "invalid");
}
toggleClass(container_elem, "valid", false);
}
});
input_elem.addEventListener('keyup', (ev) => {
if (ev.keyCode == 13) {
input_elem.value = "";
input_elem.blur();
// Submit
return false;
}
});
},
};
self.init();
return self;
}
var link_input = LinkInput();
It's up to you. I think notifications should be driven by javascript as it's not part of the site at the moment it loads. Im thinking some SEO here, not that the search engines should save notifications like that anyways. Well that's my opinion :)
Cheers!
I'm using this switcher: http://widowmaker.kiev.ua/checkbox/
and I'd like to add some custom code to change a css class that decorates a container (border color) once the switch is OFF.
The CSS (sass way)
.box {
background: none repeat scroll 0 0 rgba(246, 246, 248, 0.7);
padding: 4px;
#include rounded_borders(#ccc, 0px, 6px);
& .box-border {
background: #FFFFFF no-repeat scroll left top;
#include rounded_borders(#E0E5E9, 1px, 3px);
}
}
the .JS:
(function($){
/* Little trick to remove event bubbling that causes events recursion */
var CB = function(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
};
$.fn.checkbox = function(options) {
/* IE6 background flicker fix */
try { document.execCommand('BackgroundImageCache', false, true); } catch (e) {}
/* Default settings */
var settings = {
cls: 'jquery-checkbox', /* checkbox */
empty: 'images/empty.png' /* checkbox */
};
/* Processing settings */
settings = $.extend(settings, options || {});
/* Adds check/uncheck & disable/enable events */
var addEvents = function(object)
{
var checked = object.checked;
var disabled = object.disabled;
var $object = $(object);
if ( object.stateInterval )
clearInterval(object.stateInterval);
object.stateInterval = setInterval(
function()
{
if ( object.disabled != disabled )
$object.trigger( (disabled = !!object.disabled) ? 'disable' : 'enable');
if ( object.checked != checked )
$object.trigger( (checked = !!object.checked) ? 'check' : 'uncheck')
},
10 /* in miliseconds. Low numbers this can decrease performance on slow computers, high will increase responce time */
);
return $object;
};
//try { console.log(this); } catch(e) {}
/* Wrapping all passed elements */
return this.each(function()
{
var ch = this; /* Reference to DOM Element*/
var $ch = addEvents(ch); /* Adds custom events and returns, jQuery enclosed object */
/* Removing wrapper if already applied */
if (ch.wrapper) ch.wrapper.remove();
/* Creating wrapper for checkbox and assigning "hover" event */
ch.wrapper = $('<span class="' + settings.cls + '"><span class="mark"><img src="' + settings.empty + '" /></span></span>');
ch.wrapperInner = ch.wrapper.children('span:eq(0)');
ch.wrapper.hover(
function(e) { ch.wrapperInner.addClass(settings.cls + '-hover');CB(e); },
function(e) { ch.wrapperInner.removeClass(settings.cls + '-hover');CB(e); }
);
/* Wrapping checkbox */
$ch.css({position: 'absolute', zIndex: -1, visibility: 'hidden'}).after(ch.wrapper);
/* Ttying to find "our" label */
var label = false;
if ($ch.attr('id'))
{
label = $('label[for='+$ch.attr('id')+']');
if (!label.length) label = false;
}
if (!label)
{
/* Trying to utilize "closest()" from jQuery 1.3+ */
label = $ch.closest ? $ch.closest('label') : $ch.parents('label:eq(0)');
if (!label.length) label = false;
}
/* Labe found, applying event hanlers */
if (label)
{
label.hover(
function(e) { ch.wrapper.trigger('mouseover', [e]); },
function(e) { ch.wrapper.trigger('mouseout', [e]); }
);
label.click(function(e) { $ch.trigger('click',[e]); CB(e); return false;});
}
ch.wrapper.click(function(e) { $ch.trigger('click',[e]); CB(e); return false;});
$ch.click(function(e) { CB(e); });
$ch.bind('disable', function() { ch.wrapperInner.addClass(settings.cls+'-disabled');}).bind('enable', function() { ch.wrapperInner.removeClass(settings.cls+'-disabled');});
$ch.bind('check', function() { ch.wrapper.addClass(settings.cls+'-checked' );}).bind('uncheck', function() { ch.wrapper.removeClass(settings.cls+'-checked' );});
/* Disable image drag-n-drop for IE */
$('img', ch.wrapper).bind('dragstart', function () {return false;}).bind('mousedown', function () {return false;});
/* Firefox antiselection hack */
if ( window.getSelection )
ch.wrapper.css('MozUserSelect', 'none');
/* Applying checkbox state */
if ( ch.checked )
ch.wrapper.addClass(settings.cls + '-checked');
if ( ch.disabled )
ch.wrapperInner.addClass(settings.cls + '-disabled');
});
}
})(jQuery);
Thanks!
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" type="text/javascript"></script>
<script src="jquery-ui-1.8.24.custom.min.js" type="text/javascript"></script>
<!--This has the Effects Core and all four boxes checked in the UI Core-->
<style type="text/css">
.menu {
height: 35px;
padding: 15px 20px 5px 20px;
font-family: 'Open Sans Condensed', sans-serif;
font-size: 1.3em;
font-weight: bold;
display: inline;
float: right;
background: none;
}
.menu-hover {
height: 35px;
padding: 15px 20px 5px 20px;
font-family: 'Open Sans Condensed', sans-serif;
font-size: 1.3em;
font-weight: bold;
display: inline;
float: right;
background: url(../img/header-bg2.png) repeat-x;
}
</style>
<script>
$(document).ready(function () {
$('.menu').hover(function () {
setTimeout($(this).addClass("menu-hover"), 1000);
}, function () {
setTimeout($(this).removeClass("menu-hover"), 1000);
});
});
</script>
<div class="menu">Contact</div>
<div class="menu">Services</div>
<div class="menu">About</div>
<div class="menu">Home</div>