True CSS Positioned Float - css

http://www.w3.org/TR/css3-exclusions/
Is what I need and IE supports it as can be demonstrated nicely at http://ie.microsoft.com/testdrive/html5/positionedfloats/default.html
however no other browsers seem to support the wrap-flow attribute.
How do I achieve a positioned float on any browser other than IE? (The "excluded block" can be at a fixed position, however everything surrounding it is dynamic in nature.)
Note I have tried the css "shape-outside" attribute: http://jsfiddle.net/ourk5mue/
-webkit-shape-outside: polygon(0px 280px, 100% 280px, 100% 500px, 0px 500px);
however the results are either unreliable (due to occationally disabling line breaking (as seen on chrome)), or not supported (on firefox).
It looks like I'll have to use javascript to manually relocate the DOM element in the document flow. Can this be done only with CSS?

Ended up doing something like this:
I execute a function that relocates the target block whenever the surrounding angular ng-repeat blocks change or if the window resizes.
app.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('ngRepeatFinished');
});
}
}
};
});
var injectItem = function(ngRepeatFinishedEvent) {
if (typeof(ngRepeatFinishedEvent) !== "undefined") {
if (typeof(ngRepeatFinishedEvent.targetScope.item) === "undefined") {return;}
//other validation
}
var index = 2;
if (window.innerWidth < 1200) {index=1;}
if (window.innerWidth < 768) {index=0;}
var secondRow = jQuery('.items').eq(index);
var injectable = jQuery(".injectable").eq(0);
if (!secondRow.next().hasClass('injectable')) {
jQuery(".injectable:not(:first)").remove();
secondRow.after(injectable.clone().css('display', 'block'));
}
};
$scope.$on('ngRepeatFinished', injectItem);
window.addEventListener('resize', function() {
injectItem();
});
<span class="injectable" style="display: none;">sorta fixed position blah</span>
<span ng-repeat="item in items" on-finish-render class="item">
surrounding blah
</span>
this answer is based on Calling a function when ng-repeat has finished

Related

How to prevent display of Angular mat-menu-panel until after completion of CSS transform

Working on an Angular 14 application, I want all context menu pop-ups to be only 80% of their size, as the default size is too large and clunky in the context of the data presented in the application. This is working fine to accomplish this:
.cdk-overlay-pane .mat-menu-panel {
transform: scale(0.8);
transform-origin: top left;
}
However, the problem is that the context menu appears at full size for a moment, and then the transform takes effect and it "snaps" to the desired size. I don't want it to appear until the transform is complete. Anybody know how to accomplish this?
I was able to do this by defaulting mat-menu-panel to visibility: hidden, then showing it a fraction of a second after the menu is opened. (I don't like using javascript like this within the context of an Angular app, but I don't know any other way.)
Default CSS:
.mat-menu-panel {
visibility:hidden;
}
Showing after menu is opened:
public onContextMenu(event: MouseEvent, item: any) {
event.preventDefault();
this.contextMenuPosition.x = event.clientX + 'px';
this.contextMenuPosition.y = event.clientY + 'px';
this.matMenuTrigger.menuData = { 'item': item };
this.matMenuTrigger.menuOpened.subscribe(() => {
setTimeout(() => {
const overlayPanes = document.getElementsByClassName('mat-menu-panel') as HTMLCollectionOf<HTMLElement>;
Array.from(overlayPanes).forEach((el) => {
el.style.visibility = 'visible';
});
}, 200);
});
this.matMenuTrigger.openMenu();
}

Hide a whole div with CSS with part of it is empty

Is there a way to hide a whole div if part of it is empty? For example if "dd" is empty as shown below can I hide the whole class "test" so the keyword Restrictions does not show either. I tried .test dd:empty { display: none; } but this does not work. thanks!
<div class="test"><dt>Restrictions:</dt>
<dd></dd></div>
I don't think there's any easy way to do what you're talking about with just CSS. Better to test it server-side if you can. But if you can't here's some JS that will do the job.
<script type="text/javascript">
// handles multiple dt/dd pairs per div and hides them each conditionally
function hideIfEmpty() {
// get all the elements with class test
var els = document.getElementsByTagName('dl');
// for every 'test' div we find, go through and hide the appropriate elements
Array.prototype.map.call(els, function(el) {
var children = el.childNodes;
var ddEmpty = false;
for(var i = children.length - 1; i >= 0; i--) {
if(children[i].tagName === 'DD' && !children[i].innerHTML.trim()) {
ddEmpty = true;
} else if(children[i].tagName === 'DT') {
if(ddEmpty) {
children[i].style.display = 'none';
}
// reset the flag
ddEmpty = false;
}
}
});
}
window.addEventListener('load', hideIfEmpty);
</script>
<div class="test">
<div style="clear: both;"></div>
<dl>
<dt>Restrictions:</dt>
<dd></dd>
<dt>Other Restrictions:</dt>
<dd>Since I have content, I won't be hidden.</dd>
</dl>
</div>
Just a fair warning: the code uses some functions that may not exist in older IE, such as Array.prototype.map, String.prototype.trim, and addEventListener. There are polyfills available for these and you could also write your own pretty easily (or just do it with a for loop instead).
CSS alone can't do that. Either, you need a javascript to retrieve empty elements and hide their parents, or your CMS applies special CSS classes if there's no content.
Put as an answer as requested by #Barett.
You could update your CSS to be
.test{
display: none;
color: transparent;
}
This would make the text transparent too, but display:none should hide it anyway.
To make the div with the id test ONLY show when the dd tag is EMPTY, and you can use jQuery, try the following JavaScript along with the CSS:
if($("dd").html().length ==0)
{show();
}
Note: this solution requires jQuery, which is a JavaScript library.

How to apply HTML5 fullscreen API to div background image

Want to apply HTML 5 fullscreen APi to background image of div
<div class="bgimg" style="background-image:url('img/home-1.jpg')" />
<img src="img/fullscreen.png" id="fullscreen-btn">
</div>
I want onclick fullscreen-btn background image of div bgimg ie home-1.jpg should open in fullscreen. I tried below code but not workin Kindlt suggest
<scritpt>
$(function() {
var bg = $('.bgimg');
$('#fullscreen-btn').click(function () {
goFullScreen(bg.attr('style', 'background-image:url()'));
});
});
function goFullScreen( element )
{
if ( element === undefined )
{
// If no element defined, use entire document
element = document.documentElement;
}
if ( element.requestFullScreen )
{
// Spec, supported by Opera 12.1+
element.requestFullScreen();
}
else if ( element.mozRequestFullScreen )
{
// Supported by Firefox 10+
element.mozRequestFullScreen();
}
else if ( element.webkitRequestFullScreen )
{
// Supported by Chrome 15+ & Safari 5.1+
element.webkitRequestFullScreen();
}
// Still no IE support, sorry folks :(
}
Seems to be working for me. You just needed to add the image path in your javascript with quotes around it.
$(function() {
var bg = $('.bgimg');
$('#fullscreen-btn').click(function () {
goFullScreen(bg.attr('style', "background-image:url('img/home-1.jpg')"));
});
});
FIDDLE
I believe, but will admit am not 100% sure, that the fullscreen API can only full screen an HTML element. So that is why it will fullscreen div.bgimg but will not fullscreen the background image of the element. <img> is an HTML element, however, so I would think that would work. Is there any reason you would not want to use that instead of setting the background image of your divs?
If so, you could try to wire up some JS that connects visible divs with the background images (Like what you have now) to invisible images and load those to your fullscreen script instead.

media query for vertical scroll

Is there a way to detect vertical scroll distance with a media query?
It seems that media queries are designed around detecting the medium (shocking right :P) so things like browser height are testable, but not specifically how far down the page is scrolled.
If is not possible, but you know a way in JS (not jQuery) feel free to post!
First off, the accepted answer doesn't work.
The correct name is
window.onscroll
and not
window.onScroll
https://developer.mozilla.org/en-US/docs/Web/API/window.onscroll
Second, this is horribly inefficient as the function is called way more than it needs to and can make the page laggy when scrolled. From John Resig:
http://ejohn.org/blog/learning-from-twitter/
Much better to use a timer that runs every 150 ms or so - something like:
var scrolled = false;
window.onscroll = function() {
scrolled = true;
}
setInterval(function(){
if (scrolled) {
scrolled = false;
// scrollFunction()
}
}, 150);
I don't believe it's possible with a CSS media query, but I do know that the scroll height can be found in JavaScript using window.pageYOffset. If you wanted to run this value through a function every time the users scrolled up or down on a page, you could do something like
window.onscroll = function() {
scrollFunctionHere(window.pageYOffset);
};
Or just:
window.onscroll = scrollFunctionHere;
If the function itself checked the value of window.pageYOffset.
For more advice on how to do use window.onscroll efficiently in JavaScript, refer to mynameistechno's answer.
Important note on efficiency: running a function every single time a scroll event is emitted can tear through CPU cycles if anything non-trivial is performed in the callback. Instead, it is good practice to only allow a callback to run so many times per second. This has been termed "debouncing".
Simple debounced scroll event handler code below. Notice how the text toggles between "HELLO" and "WORLD" every 250ms, rather than every single frame:
var outputTo = document.querySelector(".output");
var timeout_debounce;
window.addEventListener("scroll", debounce);
function debounce(event) {
if(timeout_debounce) {
return;
}
timeout_debounce = setTimeout(clearDebounce, 250);
// Pass the event to the actual callback.
actualCallback(event);
}
function clearDebounce() {
timeout_debounce = null;
}
function actualCallback(event) {
// Perform your logic here with no CPU hogging.
outputTo.innerText = outputTo.innerText === "HELLO"
? "WORLD"
: "HELLO";
}
p {
padding: 40vh;
margin: 20vh;
background: blue;
color: white;
}
<p class="output">Test!</p>
In Jquery you have the method .scrollTop()
http://api.jquery.com/scrolltop/
This example make a div scroll with the window scroll.
$(window).scroll(function(){
$("div").css("margin-top", $(window).scrollTop())
});
Here is one way to solution.f https://jsfiddle.net/oravckzx/1/
$(window).scroll(function(){
$('.post-sidebar').each(function(){
var ScrollTopVar = $(window).scrollTop();
var OffsetTopVar = $(this).offset().top;
var OuterHeightVar = $(this).outerHeight();
var PositionVar = OffsetTopVar-(OuterHeightVar*1.1);
if (ScrollTopVar >= PositionVar) {
$('.hide') .css('background','green').css('font-size','12px')
$('.post-sidebar') .css('background','orange').css('font-size','12px')
$('.hide') .css('background','green').css('font-size','12px')
$('.post-sidebar') .css('background','gray').css('font-size','12px')
document.getElementById("demo3").innerHTML = ScrollTopVar;
document.getElementById("demo2").innerHTML = PositionVar;
}else {
$('.hide') .css('background','yellow').css('background','yellow')
$('.hide') .css('background','yellow')
$('.hide') .css('background','yellow')
document.getElementById("demo").innerHTML = ScrollTopVar;
document.getElementById("demo12").innerHTML = ScrollTopVar;
document.getElementById("demo13").innerHTML = ScrollTopVar;
document.getElementById("demo14").innerHTML = ScrollTopVar;
document.getElementById("demo2").innerHTML = PositionVar;
}
});
});
.red {height:100px;
background:red;margin-bottom:20px;}
.hide {height:50px;background:blue;margin-bottom:20px;}
.post-sidebar {
height:50px;
background:yellow;
margin-bottom:20px;
box-sizing: border-box;
display: block;
font: normal 700 34px Lato, sans-serif;
padding-right: 20px;
width: 452px;
}
.p {
font: normal 700 14px Lato, sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="red"><p id="demo"></div>
<div class="red"></div><p id="demo12">ok
<div class="red"><p id="demo13">ok</div>
<div class="post-sidebar"><p id="demo2"></p><p>lizard</p></div>
<div class="hide"><p id="demo2">If reaches to chosen class in html, saves value of ScrollTopVar (as distance from top) to separate variable as eventually PositionVar (which is the distance from top to the chosen class in html, - and that specific distance depends of device which is doing it), and then does certain action if ScrollTopVar value matches or exceeds PositionVar value. Else sets it back if needed, if not including Else it remains as it once met the value. <p id="demo3"></div>
<div class="red"><p id="demo14">ok</div>
<div class="red"><p id="demo"></div>
<div class="red"><p id="demo"></div>

Auto-resize an image in CSS without replacing HTML width / height attributes?

I'm trying to make an image fit nicely on different screen sizes without breaking the layout. The following bit of CSS helps:
.viewer .main img {
max-width: 100%;
height: auto;
}
But the trouble is this image changes. I use a bit of Javascript to create a new img element each time the image changes, instead of reusing the existing one. (This seems a little more reliable for what I'm doing). The browser doesn't know the image's size until it is loaded, creating an obvious flicker in the interim. I deal with that by setting the image's width and height attributes in HTML. Without the above CSS rule, that works fine.
With that CSS, the flickering is still there. For some reason, when I create a new img element, the CSS seems to be causing the browser to ignore its width and height attributes, so. It ends up as ignorant of the aspect ratio as it was before.
Here's a jsfiddle to illustrate the situation:
http://jsfiddle.net/7sDtN/
One of the images in there is very very big (138 MB), so be careful if you're on a metered connection :)
What I would love is to get the image to scale according to those dimensions I set in HTML. Preferably in a nice way. A Javascript solution isn't the end of the world (I'm already using it, for course), but if there's an elegant CSS solution that would be very nice.
I ended up solving this in a roundabout way by wrapping the image in a dedicated container, along with some strange looking javascript to keep it in place as the image loads. The dimensions for that container are calculated as in Sven's answer, but ultimately it lets the browser take over. This way layout changes are kept fairly minimal and we end up only doing this crazy stuff for the bit of time between images.
Here's a big wad of code, for completedness:
function Viewer(container) {
var viewer = this;
container = $(container);
var pictureBox = $('.picture', container);
var img = $('<img>').appendTo(pictureBox);
var hide = function() {
/* [snip] */
}
var getPictureDisplayHeight = function(picture) {
var ratio = picture.data.h / picture.data.w;
var displayWidth = Math.min(pictureBox.width(), picture.data.w);
var displayHeight = Math.min(displayWidth * ratio, picture.data.h);
return displayHeight;
}
var stopLoadingTimeoutId = undefined;
var stopLoadingTimeout = function() {
container.removeClass('loading');
}
var showPicture = function(picture) {
var imgIsChanging = img.data('picture') != picture;
container.show();
/* This code expects to be cleaned up by stopLoadingTimeout or onImgLoaded, which will not fire if img src doesn't change */
if (imgIsChanging) {
container.addClass('loading');
window.clearTimeout(stopLoadingTimeoutId);
stopLoadingTimeoutId = window.setTimeout(stopLoadingTimeout, 3000);
}
pictureBox.css({
'min-height' : pictureBox.height()
});
var displayHeight = getPictureDisplayHeight(picture);
if (displayHeight > pictureBox.height()) {
/* Grow pictureBox if necessary */
pictureBox.stop(true, false);
pictureBox.animate({
'height' : displayHeight
}, 150);
}
/* I wish I could set width and height here, but it causes the current image to stretch */
img.attr({
'src' : picture.fullPath
}).data('picture', picture);
}
var onImgLoaded = function(event) {
/* The load event might not be fired, so nothing here should be essential */
var picture = img.data('picture');
container.removeClass('loading');
var displayHeight = getPictureDisplayHeight(picture);
pictureBox.stop(true, false);
pictureBox.animate({
'min-height' : 0,
'height' : displayHeight
}, 150, function() {
pictureBox.css('height', 'auto');
});
window.clearTimeout(stopLoadingTimeoutId);
}
var onImgClicked = function(event) {
selectNextPicture();
}
var onPictureSelectedCb = function(picture) {
if (picture) {
showPicture(picture);
} else {
hide();
}
}
var init = function() {
img.on('click', onImgClicked);
img.on('load', onImgLoaded);
}
init();
}
Relevant HTML:
<div class="viewer" style="display: none;">
<div class="picture"></div>
<div class="caption"><div class="caption-text"></div></div>
</div>
And CSS:
.viewer .picture img {
display: block;
margin: 0 auto;
max-width: 100%;
height: auto;
}
This way we leave space around the image that is either the size of the next image or the size of the current image, and never the smaller size that seems to happen before a new image is loaded (which kept happening for some reason). There are probably a million solutions to this, and mine doesn't feel especially straight-forward, so I'm certainly curious to see others :)
If I understand you right, you can achieve your goal by using the following code
HTML
<div id="Wrapper">
<img id="MyPic" src="http://www.davidstorey.tv/wp-content/uploads/2012/05/image.php_.jpeg" alt="" width="300" height="200" />
</div>
CSS
body{
width:100%;
}
#Wrapper{
width:98%;
border:1px solid red;
}
jQuery
$("document").ready(function(){
var ratio=$("#MyPic").width() / $("#MyPic").height();
$("#MyPic").css("width","100%");
$("#MyPic").css("height", $("#MyPic").width()/ratio+"px");
});
Here is the link to jsfiddle

Resources