CSS/JS: Animate Inline Element Upon Text Change - javascript

When an inline element's text changes, it is usually the case that its computed width or height changes as well.
Usually it's trivial to transition property changes with CSS, for example, adding a transition to change the background-color of an element upon hover.
However, inline element dimensions are really tricky. A simple transition property does not animate the change in computed width.
View example an by clicking here: https://jsfiddle.net/mz103/59s42ys4/ or viewing it below:
$("div").on("click", function() {
$(this).text("Although my width changes, it is not aniamted.");
});
div {
display: inline-block;
background-color: red;
padding: 8px 16px;
transition: width 0.3s; // Notice, this doesn't transition the width upon change.
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Click me.</div>
How, when the text of an inline element changes, can we animate those changes?

Here an Update: https://jsfiddle.net/ky3c5Lec/3/
$("div").on("click", function() {
//get the current Dimensions, as Start-value for the animation
var $this = $(this),
sw = $this.width(),
sh = $this.height();
$this.text("New text");
var tw = $this.width(),
th = $this.height();
$this.css({
//since jQuery.animate() doesn't have sth. like Tween.from()
//we have to reset the styles to the initial values
width: sw, height: sh
}).animate({
//and then animate
width: tw, height: th
}, function(){
//and when the animation is done, we clean up after ourselves
$this.css({
width: "", height: ""
});
})
});

You could try a little bit of jQuery animation:
function changeText(el) {
el.animate(
{
opacity: 0
},
{
duration: 'slow',
complete: function () {
$(this).text('New Text');
$(this).animate({opacity: 1}, 'slow');
}
});
}
Here is a fiddle.

I suppose that you will need two elements to achieve this elegantly:
$(".inner").on("click", function() {
var $this = $(this);
var $par = $this.parent();
$par.css({
width: $par.width()
});
$this.text("New text");
$par.css({
width: $this.outerWidth()
});
});
.inner {
display: inline-block;
padding: 8px 16px;
white-space: nowrap;
}
.outer {
display: inline-block;
transition: width 300ms ease-in-out;
background-color: red;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">Here's some text.</div>
</div>

Related

jQuery code disabling links to other web pages

I have some jQuery code that allows for smoothing scrolling on my web pages.
$(document).ready(function(){
// browser window scroll position (in pixels) where the button will appear
var offset = 200,
// duration of the animation (in ms)
scroll_top_duration = 700,
// bind with the button
$back_to_top = $('.back-to-top');
// display and hide the button
$(window).scroll(function(){
( $(this).scrollTop() > offset ) ? $back_to_top.addClass('make-visible-btt') : $back_to_top.removeClass('make-visible-btt');
});
//smooth scroll to top
$back_to_top.on('click', function(event){
event.preventDefault();
$('body,html').animate({
scrollTop: 0 ,
}, scroll_top_duration
);
});
});
$(document).ready(function() {
// browser window scroll position (in pixels) where the button will appear
var offset = 200,
// duration of the animation (in ms)
scroll_top_duration = 700,
// bind with the button
$back_to_top = $('.back-to-top');
// display and hide the button
$(window).scroll(function() {
($(this).scrollTop() > offset) ? $back_to_top.addClass('make-visible-btt'): $back_to_top.removeClass('make-visible-btt');
});
//smooth scroll to top
$back_to_top.on('click', function(event) {
event.preventDefault();
$('body,html').animate({
scrollTop: 0,
}, scroll_top_duration);
});
});
.back-to-top {
position: fixed;
bottom: 20px;
right: 20px;
display: inline-block;
height: 40px;
width: 40px;
background: url(../images/back-to-top.png) no-repeat;
background-size: contain;
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
border: 1px solid #aaa;
visibility: hidden;
opacity: 0;
transition: opacity .3s 0s, visibility 0s .3s;
}
.make-visible-btt {
visibility: visible;
opacity: 1;
transition: opacity 1s 0s, visibility 0s 0s;
}
.section {
border: 1px solid black;
background-color: #ededed;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
jump to last section
<div class="section"></div>
<div class="section"></div>
<div class="section"></div>
<div class="section"></div>
<div class="section" id="last"></div>
Back to Top
The code works fine. When users click the "back to top" button on the page, they're automatically smooth scrolled to the top. All good.
The code above, however, doesn't work for in-page links.
text text text
So if a user clicks on a link like the one above, the pages instantly jumps to that section (which is the default behavior).
I added this code to fix that problem:
$(document).ready(function(){
$('a[href*="\\#"]').on('click', function(event){
var href = $(event.target).closest('a').attr('href'),
skip = false;
if (!skip) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);
}
});
});
$(document).ready(function() {
// browser window scroll position (in pixels) where the button will appear
var offset = 200,
// duration of the animation (in ms)
scroll_top_duration = 700,
// bind with the button
$back_to_top = $('.back-to-top');
// display and hide the button
$(window).scroll(function() {
($(this).scrollTop() > offset) ? $back_to_top.addClass('make-visible-btt'): $back_to_top.removeClass('make-visible-btt');
});
//smooth scroll to top
$back_to_top.on('click', function(event) {
event.preventDefault();
$('body,html').animate({
scrollTop: 0,
}, scroll_top_duration);
});
});
$(document).ready(function(){
$('a[href*="\\#"]').on('click', function(event){
var href = $(event.target).closest('a').attr('href'),
skip = false;
if (!skip) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);
}
});
});
.back-to-top {
position: fixed;
bottom: 20px;
right: 20px;
display: inline-block;
height: 40px;
width: 40px;
background: url(../images/back-to-top.png) no-repeat;
background-size: contain;
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
border: 1px solid #aaa;
visibility: hidden;
opacity: 0;
transition: opacity .3s 0s, visibility 0s .3s;
}
.make-visible-btt {
visibility: visible;
opacity: 1;
transition: opacity 1s 0s, visibility 0s 0s;
}
.section {
border: 1px solid black;
background-color: #ededed;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
jump to last section
<div class="section"></div>
<div class="section"></div>
<div class="section"></div>
<div class="section"></div>
<div class="section" id="last"></div>
Back to Top
So now that's fixed.
But that second code block has created two new problems:
Links with a fragment identifier (e.g., #section-of-page) no longer update in the browser address bar. For example, within a page, on click, the page does scroll smoothly to the target section (so it works), but the web address stays fixed at www.website.com/whatever, when it should update to www.website.com/whatever#section-of-page.
Links with a fragment identifier don't work across pages. In other words, /this-web-page#section-of-page works fine. But /another-web-page#section-of-page and www.another-website.com/whatever#section-of-page both fail (click does nothing).
These problems didn't exist before adding that second code block.
Looking for some guidance on how to fix these problems.
Also if you can suggest a way to integrate all functions into one block of code, that would be great.
Lastly, I know about the CSS scroll-behavior property, but it's still very rudimentary (can't adjust any settings), so I'd rather stick with JS for now.
Thanks.
You can check if the href points to an internal location by creating a URL object from it and checking its host against window.location.host. Then call event.preventDefault and perform smooth scrolling only in that case.
The callback function (third argument) to $.animate can be used to set the hash properly after the scrolling effect.
if (new URL(href, window.location).host === window.location.host) {
event.preventDefault();
$('html,body').animate({
scrollTop: $(this.hash).offset().top
}, 500, function() {
window.location.hash = new URL(href, window.location).hash;
});
}
$(document).ready(function() {
// browser window scroll position (in pixels) where the button will appear
var offset = 200,
// duration of the animation (in ms)
scroll_top_duration = 700,
// bind with the button
$back_to_top = $('.back-to-top');
// display and hide the button
$(window).scroll(function() {
($(this).scrollTop() > offset) ? $back_to_top.addClass('make-visible-btt'): $back_to_top.removeClass('make-visible-btt');
});
//smooth scroll to top
$back_to_top.on('click', function(event) {
event.preventDefault();
$('body,html').animate({
scrollTop: 0,
}, scroll_top_duration);
});
});
$(document).ready(function(){
$('a[href*="\\#"]').on('click', function(event){
var href = $(event.target).closest('a').attr('href');
if (new URL(href, window.location).host === window.location.host) {
event.preventDefault();
$('html,body').animate({
scrollTop: $(this.hash).offset().top
}, 500, function() {
window.location.hash = new URL(href, window.location).hash;
});
}
});
});
.back-to-top {
position: fixed;
bottom: 20px;
right: 20px;
display: inline-block;
height: 40px;
width: 40px;
background: url(../images/back-to-top.png) no-repeat;
background-size: contain;
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
border: 1px solid #aaa;
visibility: hidden;
opacity: 0;
transition: opacity .3s 0s, visibility 0s .3s;
}
.make-visible-btt {
visibility: visible;
opacity: 1;
transition: opacity 1s 0s, visibility 0s 0s;
}
.section {
border: 1px solid black;
background-color: #ededed;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
jump to last section
External link
<div class="section"></div>
<div class="section"></div>
<div class="section"></div>
<div class="section"></div>
<div class="section" id="last"></div>
Back to Top
for The 1st problem is because of event.preventDefault();. If you remove this line then browser url will be updated accordingly.
if you see any problems then you try setting the url again after animation completes / finishes.
for syntax refer docs
$('html,body').animate({
scrollTop: $(href).offset().top
}, 500, function () {
window.location.hash = href;
});
For 2nd problem
check wether the callback is hitting on click by putting debug point

Unable to retrieve Height from a toggleClass jQuery

I want to get the height of a class that is toggled. When a button is clicked, the class .category-menu-visible is added. If the class exists, then I want to get it's height. But when I alert menuHeight, it is 0.
Small scale JSFiddle example
Actual Code:
jQuery
jQuery('.topics-btn').click(function(){
jQuery('.category-menu-wrap').toggleClass('category-menu-visible');
if (jQuery('.category-menu-wrap').hasClass('category-menu-visible')){
var menuHeight = jQuery('.category-menu-visible').height();
alert(menuHeight);
jQuery('.sidebar .content-wrap').css('margin-top', menuHeight);
} else {
jQuery('.sidebar .content-wrap').css('margin-top', 0);
}
});
CSS:
.category-menu-wrap {
width:100%;
height:0px;
background-color:#F7D5B6;
overflow: hidden;
transition: height .5s cubic-bezier(.27,1.76,.95,1.19);
}
.category-menu-visible {
height: 70px;
transition: height .3s cubic-bezier(.27,1.76,.95,1.1);
}
Why can't it retrieve the height?
You need to wait till transition finishes.
Update:
There is a useful event transitionend to do it:
jQuery('.topics-btn').click(function(){
var $menu = jQuery('.category-menu-wrap');
$menu.toggleClass('category-menu-visible');
$menu.on("transitionend", function(){
if (jQuery('.category-menu-wrap').hasClass('category-menu-visible')){
var menuHeight = jQuery('.category-menu-visible').height();
alert(menuHeight);
jQuery('.sidebar .content-wrap').css('margin-top', menuHeight);
} else {
jQuery('.sidebar .content-wrap').css('margin-top', 0);
}
});
});
.category-menu-wrap {
height: 0;
}
.category-menu-visible {
height: 70px;
transition: height .3s cubic-bezier(.27,1.76,.95,1.1);
}
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<button class='topics-btn'>Click</button>
<div class='category-menu-wrap'></div>
The problem you are having is the CSS transition. When you click the height is calculated but at that moment it is 0. After the transition it will have the 70px value. You need to get the height after the transition finishes.
In this example the transition duration is set to 0s.
jQuery('.topics-btn').click(function(){
jQuery('.category-menu-wrap').toggleClass('category-menu-visible');
if (jQuery('.category-menu-wrap').hasClass('category-menu-visible')){
var menuHeight = jQuery('.category-menu-visible').height();
alert(menuHeight);
jQuery('.sidebar .content-wrap').css('margin-top', menuHeight);
} else {
jQuery('.sidebar .content-wrap').css('margin-top', 0);
}
});
.category-menu-wrap {
width:100%;
height:0px;
background-color:#F7D5B6;
overflow: hidden;
transition: height 0s cubic-bezier(.27,1.76,.95,1.19);
}
.category-menu-visible {
height: 70px;
transition: height 0s cubic-bezier(.27,1.76,.95,1.1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="topics-btn">.topics-btn</button>
<div class="category-menu-wrap"></div>
In this other example we rely on the transitionend event to get the height value:
jQuery('.topics-btn').click(function(){
jQuery('.category-menu-wrap').toggleClass('category-menu-visible');
});
jQuery('.category-menu-wrap').on('transitionend',function(){
if (jQuery('.category-menu-wrap').hasClass('category-menu-visible')){
var menuHeight = jQuery('.category-menu-visible').height();
alert(menuHeight);
jQuery('.sidebar .content-wrap').css('margin-top', menuHeight);
} else {
jQuery('.sidebar .content-wrap').css('margin-top', 0);
}
});
.category-menu-wrap {
width:100%;
height:0px;
background-color:#F7D5B6;
overflow: hidden;
transition: height 0.5s cubic-bezier(.27,1.76,.95,1.19);
}
.category-menu-visible {
height: 70px;
transition: height 0.5s cubic-bezier(.27,1.76,.95,1.1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="topics-btn">.topics-btn</button>
<div class="category-menu-wrap"></div>
From the official docs
The value reported by .height() is not guaranteed to be accurate when the element or its parent is hidden. To get an accurate value, ensure the element is visible before using .height()
The problem here is exactly this: your .category-menu-visible is not visible. when JQuery looks for it. This is due to the transition property set with a duration on the toggled class.
Update (according to JSFiddle)
It appears that when toggling a class, the height isn't recognized on the toggled class unless a unit of measurement is specified.
This occurs even without the transition property.
Not working example - height: 70;
Working Example - height: 70px;

Why does this ternary operator for toggling animation in jQuery not work?

I want a div#words_3 to slowly toggle its width when I click .read_more. It works for expanding its width first, but it doesn't toggle back. Can someone help me figure out, why that is?
$('.read_more').on('click', function(e) {
e.preventDefault();
$('#words_3').animate(
{
width: (words_3.width == '85%' ? '42%' : '85%')
},1500);
});
#words_3 {
color: #fff;
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="read_more">Button</button>
<p id="words_3">Something</p>
You can do it with CSS and a class that you toggle to change the width.
I added transition: width 1.5s; to the style of the progress bar so it will animate the width for 1.5 seconds, and when you add the short class to it the width will be animated.
In the JS part, I only toggle the short class of the progressbar element to change its width from the CSS:
$('.read_more').on('click', function(e) {
e.preventDefault();
// Here I remove the `width` inline style so it won't override the CSS style
$('#words_3').css('width', '').toggleClass('short');
});
$('.random').on('click', function(e) {
e.preventDefault();
$('#words_3').css('width', Math.floor(Math.random() * (101)) + '%');
});
#words_3 {
color: #fff;
background: blue;
transition: width 1.5s;
width: 85%;
}
#words_3.short {
width: 42%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="read_more">Button</button>
<button class="random">Random</button>
<p id="words_3">Something</p>
I also added a random button that when clicked, it change the width to a random number to demonstrate how you can use it with any width value.

Animating bars to width of Text

I am creating a nav bar for my website and I want the slide outs to animate to the width of whatever text is inside it I also want everything on one line. Here is the jsfiddle and my jquery code so far
http://jsfiddle.net/2UEpd/26/
$(document).ready(function () {
$("#test").hide();
$(".title").hide();
$(".home").click(function (){
$("#test").slideToggle("slow");
});
$(".slideWrapper").hover(
function () {
$(this).children(".slideNav:eq(0)").stop().animate({
width: "112px",
height: "30px"
});
$(this).children(".slideBox:eq(0)").stop().animate({
left: "112px",
opacity: "1"
});
$(this).find(".title").show();
}, function () {
var $box = $(this).children(".slideBox:eq(0)");
$(this).children(".slideNav:eq(0)").stop().animate({
width: "0px",
height: "30px"
});
$(this).children(".slideBox:eq(0)").stop().animate({
left: "0px",
opacity: ".7"
});
$(this).find(".title").hide();
});
});
I've been trying for a while now, any help is appreciated.
Display:table propertie or inline-block would help.
An idea would be to play width text-indent and letter-spacing for instance.
Here a sample of the idea via CSS only, using table-layout properties so container fits to width used by its content text. http://codepen.io/gc-nomade/pen/kaEoe
basicly:
.slideNav {
height: 30px;
width: 0px;
padding:0 15px;/* gives it 30px width minimal */
line-height:30px;
display:table;/* shrink /expand to size needed by content */
position: relative;
white-space:nowrap;
text-indent:-3em;
letter-spacing:-1em;
transition:1s; linear ;
opacity: .7;
color: transparent;
}
.slideNav:hover {/* here set back to regular setting to layout text properly */
opacity:1;
text-indent:0em;
letter-spacing:1px;
color: white;
}
the toggle click close/open feature on menu is driven via :focus and pointer-events for demo prpose. javaScript should take care of this for a better/good practice.

How do I return the box height to original state when clicked again in JQuery?

Code:
<script type="text/javascript">
$(document).ready(function () {
$('.box').on('click', function (e) {
e.preventDefault();
var $btn = $(this);
$btn.toggleClass('opened');
var heights = $btn.hasClass('opened') ? 300 : 100;
$(this).stop().animate({ height: heights }, 800);
//$(".sync_store_info_input_holder").toggle();
});
});
</script>
CSS:
.box {
background-color: #000000;
height: 73px;
width: 269px;
margin: 40px 42px 0px 0px;
cursor: pointer;
text-align: center;
line-height: 73px;
}
The function above works fine but whenever the box is clicked open and click closed the height of the box is a bit more than the initial state. It's not a CSS issue but it seems that the height 100 in the script doesn't toggle. How can I make it so that when the box is closed the height goes back to the original state?
Problem:
It appears that the height in the function 100 remains even after the box is clicked shut. How can I make it so that when the box is closed the original height of the box is restored. The height of the box is in the .box class, which is 275px.
Maybe not the best solution, but depending on the div height this works:
jQuery/JavaScript:
var heights = $btn.hasClass('opened') ? 300 : 200;
CSS:
.box {
height: 200px;
width: 200px;
background-color: orange;
}
jsFiddle
Set your height to 73.
Change 100 to 73:
var heights = $btn.hasClass('opened') ? 300 : 73;

Categories

Resources