Marquee-like horizontal scroll without scrollbars? - javascript

I have seen both overflow scrolling with no scrollbars and Hide scrollbar for mobile devices while keeping the scroll ability ; unfortunately, both of these suggest a solution with position: absolute; and I think that I cannot really apply that to my problem.
The code in this example renders this:
Basically, the red outline boxes are divs of class .myBox, with a fixed width. These divs are side-by-side, in a container that is horizontally centered inside its container div. The top part is reserved for titles, which may be long. I'd like the titles to be rendered as on the right side one - but if they have focus, then I'd want the titles to scroll left-right with either keyboard arrow buttons, mouse wheel - or (also for mobile) dragging left and right.
Of course, since the right box's title has overflow: hidden;, there is no possibility to scroll. If I leave the scrollbar visible (overflow-x: scroll;) as on the left box, then the title is not visible at all (and I cannot scroll anyways).
So is it possible somehow to allow scrolling in the title parts of these boxes in this way (sort of like a marquee scroll behavior, but manual)?
Bonus question: is there a sort of a JavaScript library (or even better, a plain CSS solution), that would allow something similar - except, if the text is too long, it is truncated and ellipsis is added (so, instead of "My even longer" it should show "My even lon..." at start), then as you drag right to left, it also calculates ellipsis at start and at end - and when you come to the right end, it takes away the right ellipsis?
The example code is:
.mainHolder {
font-size: 14px;
border: 2px solid #999;
text-align: center; /* centers the span */
}
.centerer {
border: 2px solid #555;
display: inline-block; /* makes the span have the same width as its div contents*/
margin: 0;
padding: 0;
}
.myBox {
width: 8em;
border: 2px solid #F55;
border-radius: 0.5em;
display: inline-block; /* enables two myBox side-by-side */
}
.heading {
height: 1.25em;
border-radius: 0.25em;
background-color: #94B6F7;
overflow: hidden;
overflow-x: scroll;
}
/*just as example, remove the scroller of box2*/
#box2 .heading {
overflow-x: hidden;
}
<div class="mainHolder">
<span class="centerer">
<div id="box1" class="myBox">
<div class="heading">
My very long title
</div>
<div class="data">
Data: 1
</div>
</div>
<div id="box2" class="myBox">
<div class="heading">
My even longer title
</div>
<div class="data">
Data: 2
</div>
</div>
</span>
</div>

Related

Animate shrink and expand transitions for subsets of elements in a nested set of divs in javascript [duplicate]

This question already has answers here:
How can I transition height: 0; to height: auto; using CSS?
(41 answers)
Closed 5 years ago.
I need to animate the shrink and expand transitions for subsets of elements in a nested set of divs. The expand works fine, but the shrink is broken.
I have a structured collection of items (say, squares for purposes here) that I want to display selectively and whose transitions I want to animate.
The structure is: collection > groups > rows > squares
In static layout,
squares appear in horizontal rows;
rows are gathered vertically in groups;
a column of groups forms the collection.
Squares can be of varying sizes, so containers must adjust accordingly
(no fixed heights or widths).
I have obtained a static layout that is just what I want.
The problem comes with animation. I want to hide various subsets
of squares, rows and/or groups. Nearby items can look similar so it is
difficult for users to tell just what is being added or subtracted, so
I need a smooth animation so users can follow what is changing.
I am trying to do this with a CSS-animated shrink:
A shrinkMe class marks all element that I will want to
shrink/expand at the moment
CSS transition times are set for these
shrinkMe elements
A shrunken class is defined whose CSS has all its
size parameters set to 0
To shrink or expand, jQuery adds or removes
the the shrunken class tag to the $('shrinkMe') items, to animate
items between the full and shrunken (=0) sizes
The un-shrink animated transition is exactly what I want. But the shrink animation does not work at all - contents spill out of containers along the way.
shrink = function(bool,nsec) {
$('.shrinkMe').css("transition", 'all ' + nsec+ 's');
if (bool) $('.shrinkMe').addClass('shrunk')
else $('.shrinkMe').removeClass('shrunk');
}
anim = function(secs) {
return 'all ' + secs + 's'
}
.controls {
display: inline-block;
vertical-align: top;
}
.collection {
display: inline;
text-align: center;
border: 2px solid black;
padding: 3px;
display: inline-block;
}
.group {
display: block;
margin: 2px;
border: 2px solid black;
padding: 3px;
}
.row {
display: block;
vertical-align: middle;
background: #0cc;
margin: 1px;
border: 2px solid black;
}
.sq {
display: inline-block;
background: white;
width: 20px;
height: 20px;
margin: 5px;
border: 2px solid black;
}
.lg {
width: 25px;
height: 25px;
}
.shrinkMe {
border-color: red;
}
.shrunk {
height: 0px;
width: 0px;
border-width: 0px;
padding: 0px;
margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<div class='controls'>
<button type='button' onclick='shrink(true,2)'>shrink reds </button>
<br>
<button type='button' onclick='shrink(false,2)'>unshrink reds </button>
</div>
<div class='collection'>
<div class='group'>
<div class='row '>
<div class='sq'></div>
<div class='sq'></div>
</div>
<div class='row shrinkMe'>
<div class='sq lg shrinkMe'></div>
<div class='sq shrinkMe'></div>
<div class='sq lg shrinkMe'></div>
</div>
</div>
<div class='group shrinkMe' id='group2'>
<div class='row shrinkMe' id='group2container2'>
<div class='sq shrinkMe'></div>
<div class='sq shrinkMe'></div>
</div>
<div class='row shrinkMe'>
<div class='sq shrinkMe'></div>
<div class='sq lg shrinkMe'></div>
<div class='sq shrinkMe'></div>
</div>
</div>
</div>
Among other things, I've tried using different explicit transition speeds, so containers shrink more slowly than their contents, but to no avail. If I set explicit heights and widths of the rows and groups, I can get a coordinated nested-shrink but it is ugly:
It shrinks by squashing to the left side and;
The final layouts can have empty spaces in them (e.g., when a row shrinks inside an unshrunk group, the fixed explicit group container height means there is now a hole where the row was).
What I want is to achieve is simple: a shrink animation that is the time-reverse of the nice clean un-shrink.
Here also is a jsfiddle showing the problem that additionally has buttons for trying separate timings of more deeply nested divs (which
does not help...)
https://jsfiddle.net/furnas/dgq8yusy/
Any explanation of what is going wrong and suggestions on how to fix
it?
Use jquery anymation onComplete event for adding and removing classes to divs.
because your css transition works like asyncronous method on another thread, so, you need to wait for it to complete and than add/remove classes.
http://api.jquery.com/animate/

Why does the DIV not expand to display text

Fiddle: https://jsfiddle.net/st8q8z5g/5/
Partial CSS:
* {
padding: 0;
margin: 0;
}
body {
font-family: Verdana, Tahoma;
font-size: 11px;
}
b.title {
color: #FFFFFF;
clear: both;
display:inline-block;
padding: 0 0 5px 0;
font-size: 12px;
text-transform: capitalize;
}
b.message {
color: #EDEDED;
clear: both;
display:block;
}
I am running into two issues:
Why does the text alert get cut off if the screen is less than 820px?
(Would like the DIV to expand to show the alert automatically without
setting a height)
When pressing the "Pause" button the "Play" button is displayed but
it loses the CSS for the WIDTH and MARGIN. (The "Play" button does
not stretch and does not have the margin like the "Pause" button) [FIXED]
How can I fix the above issues.
I guess you can do a workaround where you can manually set the height of the blue container divs.
You can change the html like this:
HTML
<div class="blue-container" style="position: relative; overflow: hidden; width: 98%; padding: 1%; background: #0070C6;">
<div style="overflow: hidden; clear: both; text-align: left; position: absolute; right: 2%; top: 8%; z-index: 9999999; color: #FFF;">
<span id="msgCurr">1</span>/<span id="msgOf"></span>
</div>
<div class="light-blue-container" style="position: relative; overflow: hidden; width: 100%; margin: 0 auto; background: #009DF5;">
<div class="section group brClear">
<div class="col span_short vertAlignT span_pad_all">
Previous
Play
Pause
Next
</div>
<div class="col span_long vertAlignT span_pad_all alertHolder">
<div class="msgAlert">
<b class="title">The title alert goes here #1</b>
<b class="message">The alert message will go here 1...</b>
</div>
<div class="msgAlert">
<b class="title">The title alert goes here #2</b>
<b class="message">The alert message will go here 2...</b>
</div>
<div class="msgAlert">
<b class="title">The title alert goes here #3</b>
<b class="message">The alert message will go here 3...</b>
</div>
<div class="msgAlert">
<b class="title">The title alert goes here #4</b>
<b class="message">The alert message will go here 4...</b>
</div>
</div>
</div>
</div>
</div>
And in the css, what you can do is, using a media query, keep it like this:
CSS
#media only screen and (max-width: 820px) {
.light-blue-container{
height:100%
}
.blue-container{
height:21em
}
...
Here is fiddle:
JS fiddle : https://jsfiddle.net/st8q8z5g/9/
As you are keeping the msgAlert div position to absolute, it fixes the fade problems, but when you change the screen size, it would need to act as if its position is relative but should also have the fade smoothness, which i think might be difficult to achieve. So instead of that, just change the containers height and set it manually when the screen size is less than 820px. But if you are unwilling to compromise the dynamic height, you can achieve it using jquery or javascript. But I think for now this should solve your problem.
Why does the text alert get cut off if the screen is less than 820px? (Would like the DIV to expand to show the alert automatically without setting a height)
The .msgAlert has position: absolute and the absolutely positioned elements do not take any height in the viewport. Removing position: absolute from there works:
.msgAlert {
/* position: absolute; */
display: none;
clear: both;
overflow: hidden;
}
When pressing the "Pause" button the "Play" button is displayed but it loses the CSS for the WIDTH and MARGIN. (The "Play" button does not stretch and does not have the margin like the "Pause" button)
The #playAlert has display: inline set very hard, even though if you change, it doesn't. It has to be block.
You can fix it using:
$('#playAlert').css("display", "block").hide();
If I remove position: absolute the message jumps as it fades out and then in...
Give a min-height for the container so that it doesn't jump. :)
The "Play" button isn't the same width if I use your fiddle :/
I left this for you to figure out intentionally. But you made to answer this. Here's the solution:
$('#playAlert').css("display", "inline-block").hide();
Working Fiddle: https://jsfiddle.net/e34pzhu3/

highlighting characters in text depending on position of page

I have a text on my website that scrolls horizontal through the page. I’m trying to get around 8 characters highlighted in black, while the rest is grey. But those characters are meant to vary as you scroll though, the highlighted bit should remain in place.
In case this doesn’t make any sense, if grey was an x, it should look something like this:
xxxxx xpsum dolox xxx xxxx
xxxx xxsum dolox sxx xxxx
xxx xxxum dolox six xxxx x
xx xxxxm dolox sit xxxx xx
I’m trying to get this done in jQuery, but I can’t get it to work. I also like to say that I’m not at all an expert in webdesign, so I don’t know what I’m doing. Anyway, I’ve tried two different approaches, one is to say “change colour of text when going over an underlying div”. The other approach is to change the colour of the text depending on the scrolling position, but the problem here is that it takes the scrolling position of the whole div, instead of a fixed position on the page. Both don’t work at the moment, examples are here:
jsfiddle 9p29tz2f
jsfiddle 9p29tz2f/1
If anyone has any ideas how to approach this, or needs some more clarification, please let me know. Many thanks!
Clone the text and set it as a child of the overlay box then scroll them together:
$(function(){
var $bodytext = $('#bodytext'),
$clone = $bodytext.clone();
//copy the text and append it to #black:
$clone.attr("id","clone").prependTo("#black");
//scroll #clone with #bodytext:
$bodytext.scroll(function(){
$clone.scrollLeft($bodytext.scrollLeft());
});
});
http://jsfiddle.net/9p29tz2f/2/
I've taken Teemu's solution and modified it a bit: http://jsfiddle.net/9af91wcL/2/
The important bits: The code moves a white DIV (#grey-overlay) on top of the text and makes it transparent. By adding black and white pixels, you get grey. The grey level is determined by the alpha channel (0.7 in the rgba() function).
You need to assign a height or it will look odd. I use 1.5em to make sure it doesn't overlap with the scroll bar of the #bodytext div.
Also make sure that the top/left position of both div's is the same.
In your real code, you can make the horizontal scrollbar disappear and scroll with JavaScript.
HTML
<div id="grey-overlay"></div>
<div id="bodytext">text...</div>
CSS
body {
background: #ffffff;
color: #000000;
font-family: sans-serif;
font-size: 200%;
}
#bodytext {
top: 15%;
width:200px;
height: 2em;
padding: 0;
position:absolute;
overflow-x:scroll;
overflow-y:hidden;
white-space: nowrap;
}
#grey-overlay {
background-color: rgba(255, 255, 255, 0.7);
width:40px;
height: 1.5em;
top:15%;
position:fixed;
z-index: 10;
}
You need to show the same content within #black as in #bodytext, and synchronize its position relative to #bodytext scrolling. This can be achieved by using an extra wrapper around #black. Something like this:
CSS:
#cover {
top: 15%;
height:50%;
width: 120px;
padding: 0;
position:fixed;
overflow-x: hidden;
background-color: #D8D8D8;
}
#black {
color: #000000;
width:100%;
height:100%;
top:0px;
left: 0px;
position:absolute;
white-space: nowrap;
z-index: 10;
}
#bodytext {
top: 15%;
width:100%;
height:85%;
padding: 0;
position:absolute;
overflow-x:scroll;
white-space: nowrap;
color: #D8D8D8;
}
HTML:
<div id="cover">
<div id="black"></div>
</div>
JS:
$(document).ready(function () {
var black = $('#black'),
btext = $('#bodytext');
black.text(btext.text()); // Clone the content
btext.scroll(function () {
var pos = btext.scrollLeft();
black.css('left', -pos + 'px'); // Set the position to match #bodytext
});
});
A live demo at jsFiddle.
Notice, that if you need some left margin, it has also to be "calculated in" to pos.

Fixed and relative elements within a div

I'm trying to position a fixed element WITHIN a div (not the whole page) in my website.
I want the navigation (deadspin, gawer, awl, other) to be fixed within the writing section so that even when user scrolls, the nav is still there. But currently it's fixed for the whole page.
As you can see on my test page, the navigation is fixed the way I want it to be.
I tried messing around with position:relative/position:fixed for the #small-box-links but that doesn't help.
.home_writing {
display: block;
position: relative;
background: rgba(50, 50, 50, 0);
height: 1000px;
text-align: left;
}
#small-box-container {
border: 1px solid black;
background: rgba(10, 200, 10, 0);
width: 980px;
height: 800px;
overflow: auto;
}
#small-box-links {
position: relative;
margin-left: 700px;
height: 25px;
margin-top: 10px;
}
<div id="small-box-container">
<div id="small-box-links">
deadspin |
gawker |
the awl |
other
</div>
<div style='overflow:hidden; width:980px;'>
<div style='overflow:scroll; width:988px'>
<div id="small-box1" class="small-box">
<h2>deadspin</h2>
<h3>How Pat Summitt Ruined The Best Thing About Women's Basketball</h3>
<!-- etc. for other boxes -->
I found this related question and yet when I try top / left, etc., the element is still fixed to the page, not writing div. (I tried making the parent element, .home_writing, relative but this doesn't fix my issue.)
(On another note, I can't figure out why my Playfair in the paragraphs doesn't look like the sidebar navigation. It's styled the same way).
position:fixed always uses the viewport as the frame of reference, so you can’t use that here.
But the solution is rather simple - use position:absolute instead to position the navigation inside a container element that has position:relative (and a fixed height), and then have the content as a sibling inside that container as well, with fixed height and overflow:auto for that element:
<div style="position:relative; height:800px;">
<div style="position:absolute; top:0; …"> [link link link] </div>
<div style="height:800px; overflow:auto;">
Lorem ipsum, dolor sit …
</div>
</div>

Position badge over corner of image automatically

I have a layout where images "float" within a certain area. The layout looks like this:
The source like this:
<div class="free_tile">
<a class="img_container canonical" href="/photos/10">
<img class="canonical" src="http://s3.amazonaws.com/t4e-development/photos/1/10/andrew_burleson_10_tile.jpg?1303238025" alt="Andrew_burleson_10_tile">
<!-- EDIT: I am aware that I can put the badge here. See the edit notes and image below. -->
</a>
<div class="location">Houston</div>
<div class="taxonomy"> T6 | Conduit | Infrastructure </div>
</div>
The CSS looks like this (in SCSS):
div.free_tile { width: 176px; height: 206px; float: left; margin: 0 20px 20px 0; position: relative;
&.last { margin: 0 0 20px 0; }
a.img_container { display: block; width: 176px; height: 158px; text-align: center; line-height: 156px; margin-bottom: 10px; }
img { margin: 0; border: 1px solid $dark3; display: inline-block; vertical-align: middle; #include boxShadow;
&.canonical { border: 1px solid $transect; }
}
.location, .taxonomy { width: 176px; }
.location { font-weight: 700; }
.taxonomy { line-height: 10px; font-size: 10px; text-transform: uppercase; height: 20px; overflow: hidden; }
}
div.transect_badge { height: 20px; width: 20px; background: url('/images/transect-badge.png'); }
So, basically the images are sitting vertically-aligned middle and text-aligned center, and they have a maximum width of 176 and max height of 158, but they're cropped to maintain the original aspect ratio so the actual top corner of each image falls differently depending on which image it is.
I have a badge that I'd like to put in the top corner of certain images (when the image is "canonical"). You see the style for this above (div.transect_badge).
The problem, of course, is I don't know where the top corner of the image will be so I can't hardcode the position via CSS.
I assume that I'll need to do this via jQuery or something. So, I started with a jQuery method to automatically append the badge div to any canonical images. That works fine, but I can't figure out how to position it over the top left corner.
How can this be done? (ideally using just HTML and CSS, but realistically using JS/jQuery)
--EDIT--
Here's the problem: The image is floating inside a container, so the corner of the image might fall anywhere inside the outer limits of the container. Here's an example of what happens if I try to use position:absolute; top:0; left:0 inside the same container the image is bound by:
It took some tryouts, but here it is: the size independent image badge positioner.
HTML:
<div class="tile">
<span class="photo">
<img src="/photos/10.jpg" alt="10" /><ins></ins>
</span>
<p class="location">Houston</p>
<p class="taxonomy">T6 | Conduit | Infrastructure</p>
</div>
CSS:
.tile {
float: left;
width: 176px;
height: 206px;
margin: 0 20px 20px 0;
}
.photo {
display: block;
width: 176px;
height: 158px;
text-align: center;
line-height: 158px;
margin-bottom: 10px;
}
a {
display: inline-block;
position: relative;
line-height: 0;
}
img {
border: none;
vertical-align: middle;
}
ins {
background: url('/images/badge.png') no-repeat 0 0;
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
}
Example:
In previous less successful attempts (see edit history), the problem was getting the image vertically centered ánd to get its parent the same size (in order to position the badge in the top-left of that parent). As inline element that parent doesn't care about the height of its contents and thus remains to small, but as block element it stretches to hís parent's size and thus got to high, see demonstration fiddle. The trick seems to be to give that parent a very small line-height (e.g. 0) and display it as an inline-block. That way the parent will grow according to its childs.
Tested in Opera 11, Chrome 11, IE8, IE9, FF4 and Safari 5 with all DTD's. IE7 fails, but a center-top alignment of the photo with badge at the right position isn't that bad at all. Works also for IE7 now because I deleted the spaces in the markup within the a tag. Haha, how weird!
EDIT3: This solution is very similar to my original solution. I didn't really look at your code much so I should have noticed this earlier. Your a tag is already wrapping each image so you can just add the badge in there and position it absolute. The a tag doesn't need width/height. Also you must add the badge image at the beginning of your a tag.
Demo: http://jsfiddle.net/wdm954/czxj2/1/
div.free_tile {
width: 176px;
height: 206px;
float: left;
}
a.img_container {
display: block;
margin-bottom: 10px;
}
span.transect_badge {
display:block;
position: absolute;
height: 20px;
width: 20px;
background-image: url('/images/transect-badge.png');
}
HTML...
<a class="img_container canonical" href="/photos/10">
<span class="transect_badge"></span>
<img class="canonical" src="path/to/img" />
</a>
Other solutions...
In my code I'm using SPAN tags so simulate images, but it's the same idea. The badge image, when positioned absolute, will create the desired effect.
Demo: http://jsfiddle.net/wdm954/62faE/
EDIT: In the case that you need jQuery to position. This should work (where .box is your container and .corner is the badge image)...
$('.box').each(function() {
$(this).find('.corner')
.css('margin-top', ( $(this).width() - $(this).find('.img').width() ) / 2);
$(this).find('.corner')
.css('margin-left', ( $(this).height() - $(this).find('.img').height() ) / 2);
});
EDIT2: Another solution would be to wrap each image with a new container. You would have to move the code that you use to center each image to the class of the new wrapping container.
Demo: http://jsfiddle.net/wdm954/62faE/1/
$('.img').wrap('<span class="imgwrap" />');
$('.imgwrap').prepend('<span class="badge" />');
Technically you can just add something like this to your HTML though without using jQuery to insert it.
Use an element other than <div>, e.g. <span> and put it inside your <a> element after the <img> element. Then, give the <a> element position:relative; and the <span> gets position:absolute; top:0px; left:0px;. That is, if you don't mind the badge also being part of the same link - but it's the easiest way. Also, the reason for using <span> is to keep your HTML4 valid, <div> would still be HTML5 valid, however.
I did find one solution using jQuery. I don't prefer this because it noticably impacts page loading, but it is acceptable if nothing else will work. I'm more interested in NGLN's idea which seems promising but I haven't entirely figured out yet. However, since this thread has picked up a lot of traffic I thought I'd post one solution that I came up with for future readers to consider:
Given this markup:
<div class="free_tile">
<a class="img_container canonical" href="/photos/10">
<img class="canonical" src="http://s3.amazonaws.com/t4e-development/photos/1/10/andrew_burleson_10_tile.jpg?1303238025" alt="Andrew_burleson_10_tile">
<span class="transect-badge"></span>
</a>
<div class="location">Houston</div>
<div class="taxonomy"> T6 | Conduit | Infrastructure </div>
</div>
Same CSS as in question except:
span.transect-badge { display: block; height: 20px; width: 20px; position: absolute; background: url('/images/transect-badge.png'); }
Then this jQuery solves the problem:
$(function() {
$('img.canonical').load( function() {
var position = $(this).position();
$(this).next().css({ 'top': position.top+1, 'left': position.left+1 });
});
});
Like I said, though, this incurs noticeable run-time on the client end, so I'd prefer to use a non JS solution if I can. I'll continue to leave this question open while I test out and give feedback on the other solutions offered, with hopes of finding one of them workable without JS.

Categories

Resources