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
Related
I have a table in which I'm trying to make the header, and an arbitrary number of columns on its left "sticky". Sticky as in, as the table data is vertically scrolled, the headers stay stuck to the top. And if there's enough columns to scroll vertically, the data and headers are vertically scrollable, but some columns stick.
Here's a table that's vertically and horizontally scrollable with sticky headers.
http://jsfiddle.net/7b29Lkwy/5/
The important parts being
.sticky-table {
width: 100%;
height: 100%;
overflow-x: scroll;
}
.scroll {
float: left; /* Makes with total content width */
min-width: 100%; /* In case there isn't enough columns */
height: calc(100% - 35px); /* Assuming we know head height */
overflow: scroll;
}
But I'm not sure how I can do this while including a sticky column.
You need some js to make it work.
The scrollbars:
<button title="Up" onmousedown="upp();" onmouseup="upp(1);">Up</button>
<button title="Left" onmousedown="left();"
onmouseup="left(1);"><<</button>
<button title="Right" onmousedown="right();"
onmouseup="right(1);">>></button>
<button title="Down" onmousedown="down();" onmouseup="down(1);">Dn</button>
Replace t1 with your table ID
if(!myTable){myTable=document.getElementById("t1");
And of course the working js
var myRow=1;
var myCol=1;
var myTable;
var noRows;
var myCells,ID;
function setUp(){
if(!myTable){myTable=document.getElementById("t1");}
myCells = myTable.rows[0].cells.length;
noRows=myTable.rows.length;
for( var x = 0; x < myTable.rows[0].cells.length; x++ ) {
colWdth=myTable.rows[0].cells[x].offsetWidth;
myTable.rows[0].cells[x].setAttribute("width",colWdth-4);
}
}
function right(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myCol<(myCells)){
for( var x = 0; x < noRows; x++ ) {
myTable.rows[x].cells[myCol].style.display="";
}
if(myCol >1){myCol--;}
ID = window.setTimeout('right()',100);
}
}
function left(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myCol<(myCells-1)){
for( var x = 0; x < noRows; x++ ) {
myTable.rows[x].cells[myCol].style.display="none";
}
myCol++
ID = window.setTimeout('left()',100);
}
}
function down(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myRow<(noRows-1)){
myTable.rows[myRow].style.display="none";
myRow++ ;
ID = window.setTimeout('down()',100);
}
}
function upp(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myRow<=noRows){
myTable.rows[myRow].style.display="";
if(myRow >1){myRow--;}
ID = window.setTimeout('upp()',100);
}
}
Refer here for the detailed explanation
http://www.codeproject.com/Articles/20017/Freeze-Panes-like-Excel
Update:
Solution to problem is to use this jquery table plugin ->
jtable
I made a calendar where I can click on each day.
When I put my mouse on the last column div, it overflows the screen width.
<div class="menu">EEEEEEE</div>
https://jsfiddle.net/c0oh7kby/
You can apply transformation on last <td>, to pull tooltip to the left:
td.ui:last-child .ui.simple.dropdown:hover > .menu {
transform: translate(calc(-100% + 16px), 0);
}
Or put it to the right:
td.ui:last-child .ui.simple.dropdown:hover > .menu {
left: auto;
right: 0;
}
updated fiddle
Edit
Before that count all menu items, that overflows viewport:
$('.ui .menu').each(function(){
var $this = $(this);
if ($this.width() + $this.parent().position().left > $(window).width()) {
$this.addClass('transformed');
}
});
And then apply needed css:
.ui.simple.dropdown:hover > .menu.transformed {
left: auto;
right: 0;
}
fiddle
However it doesn't compensate if tooltip is overflowing in both sides. for that You can check twice:
$('.ui .menu').each(function(){
var $this = $(this);
if ($this.width() + $this.parent().position().left > $(window).width()) {
$this.addClass('transformed');
if ($this.parent().position().left - $this.width() < 0) {
$this.addClass('center');
}
}
});
And apply transformation:
.ui.simple.dropdown:hover > .menu.transformed.center {
transform: translate(50%, 0);
}
fiddle
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
I'm trying to make an "image mosaic" that consists mostly of images of the same size, and some of them the double height.
They all should align neatly like this:
To make automatic generation of those mosaic as easy as possible, I thought floating them would be the best option. Unfortunately, the big block causes the following ones to flow behind it, but not before:
What can I do - apart from manually positioning them - to get the images to the place I want, and still have it easy to automatically create likewise layouts?
The code I'm currently using is :
FIDDLE
HTML :
<div class="frame">
<div id="p11" class="img">1.1</div>
<div id="p12" class="img h2">1.2</div>
<div id="p13" class="img">1.3</div>
<div id="p21" class="img">2.1</div>
<div id="p22" class="img">2.2</div>
</div>
CSS :
.frame {
background-color: blue;
border: 5px solid black;
width: 670px;
}
.img {
width: 200px;
height: 125px;
background-color: white;
border: 1px solid black;
float: left;
margin: 10px;
}
.h2 {
height: 272px;
}
You need to use Javascript to achieve this effect, I had to do that once and I used http://masonry.desandro.com/ -- worked well!
Pure CSS Solution
Tested in Firefox, IE8+ (IE7 looks like it would need to be targeted to add a top margin added to 2.1 because it overlaps 1.1). See fiddle. This assumes .h2 is the middle div (as your example). If left most div it should not need any change. If right most, you would need to expand the negative margin to also include the third div following.
.h2 + div {
float: right;
margin: 10px 14px 10px 0; /*14px I believe also has to do with borders */
}
.h2 + div + div {
margin-left: -434px; /*need to account for borders*/
clear: right;
}
You can use a column layout like this:
http://jsfiddle.net/KKUZL/
I don't know if that will conflict with your automation process though....
I realize this is not a CSS-only solution, but for what it's worth (JSFiddle):
HTML:
<div id='container'></div>
CSS:
html, body {
margin:0px;
padding:0px;
height:100%;
}
body {
background-color:#def;
}
#container {
margin:0px auto;
width:635px;
min-height:100%;
background-color:#fff;
box-shadow:0px 0px 5px #888;
box-sizing:border-box;
overflow:auto;
}
.widget {
float:left;
box-sizing:border-box;
padding:10px 10px 0px 0px;
}
.widget > div{
height:100%;
box-sizing:border-box;
color:#fff;
font-size:3em;
text-align:center;
padding:.5em;
overflow:hidden;
}
.widget > div:hover {
background-color:purple !important;
}
JS:
////////////////////////////////////////
// ASSUMPTIONS
//
var TWO_COLUMN_WIDGET_COUNT = 1;
var ONE_COLUMN_WIDGET_COUNT = 15;
var NUMBER_OF_COLUMNS = 2;
////////////////////////////////////////
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var colorFactory = (function () {
var colors = [
'#CC9A17',
'#9B2C16',
'#1A8B41',
'#D97114',
'#3B9EE6'];
var index = 0;
return function () {
if (index > 4) {
index = 0;
}
return colors[index++];
}
})();
function widgetFactory(columnSpan) {
return {
'height': rand(10, 30) * 10,
'width': 100 * columnSpan / NUMBER_OF_COLUMNS,
'columnSpan': columnSpan,
'color': colorFactory()
}
}
function getWidgets() {
var widgets = [];
for (var i = 0; i < TWO_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(2));
}
for (var i = 0; i < ONE_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(1));
}
return widgets;
}
function getHighestOffset(offsets){
}
function getHighestSlot(offsets, numOfColumns){
}
$(document).ready(function () {
var container = $('#container');
var widgets = getWidgets();
var col1 = Math.floor(container[0].offsetLeft);
var col2 = Math.floor(container[0].clientWidth / 2 + container[0].offsetLeft);
var offsets = {};
offsets[col1] = 0;
offsets[col2] = 0;
var newLine = true;
for (var i = 0; i < widgets.length; i++) {
var w = widgets[i];
var marginTop = 0;
if (offsets[col1] < offsets[col2]) {
marginTop = (offsets[col2] - offsets[col1]) * -1;
}
if(offsets[col1] <= offsets[col2] || w.columnSpan == 2){
newLine = true;
}
var margin = 'margin-top:' + marginTop + 'px;';
var height = 'height:' + w.height + 'px;';
var color = 'background-color:' + colorFactory() + ';';
var width = 'width:' + w.width + '%;';
var padding = newLine ? "padding-left:10px;" : "";
var component = $('<div class="widget" style="' + padding + margin + height + width + '"><div style="' + color + '">' + i + '</div></div>');
component.appendTo(container);
var c = component[0];
var index = 0;
var minOffset = null;
for(var p in offsets){
if(minOffset == null || offsets[p] < minOffset){
minOffset = offsets[p];
}
if(p == Math.floor(c.offsetLeft)){
index = 1;
}
if(index > 0 && index <= w.columnSpan){
offsets[p] = c.offsetTop + c.offsetHeight;
index++;
}
}
newLine = minOffset >= offsets[col1];
}
});
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').