E.g. I have the following layout:
<div contenteditable="true">
<span class="text-block" contenteditable="false">
<span contenteditable="false">Name</span>
<a href="javascript:void(0)">
<i class="small-icon-remove"></i>
</a>
</span>
</div>
So, how to disable this:
and this:
I spent on this a lot of time myself, when trying to completely hide control selections (this is how they are called) in CKEditor's widgets. Unfortunately I don't have a good news.
Solution 1
First of all, there's a mscontrolselect event. When I found it (and the fact that its name has an ms prefix) I was very happy, because according to MS it should be preventable.
But it turned out that it's totally unstable. Sometimes it is fired, sometimes it isn't. It varies between IEs versions, DOM structure, attributes, which element you click, is it a block element, etc. The usual MS's crap. But you can try:
function controlselectHandler(evt) {
evt.preventDefault();
}
document.body.addEventListener('mscontrolselect', controlselectHandler);
However, this will completely block selection (if it worked). So you'll make those elements unselectable at all.
Solution 2
Then there's a second option, more reliable - moving selection somewhere else after such element was clicked. There are few ways this can be implemented. In CKEditor we're fixing selection on mousedown... and mouseup because (again) sometimes it's not enough for IE and it depends on dozen of conditions. You could also listen to selectionchange event and fix selection there.
However, again, we're also talking about blocking selection of such element.
Solution 3
Therefore, the third option is to block not selection, but the resizestart event. CKEditor combines this with enableObjectResizing command: https://github.com/ckeditor/ckeditor-dev/blob/a81e759/plugins/wysiwygarea/plugin.js#L211-L218. This solution will prevent resizing, but of course will not hide those ugly borders.
Solution 4
As I mentioned, I worked on this problem in CKEditor. We managed to make it possible to have non-editable elements inside editable, but with completely controllable and unified behaviour between browsers. The complete solution is too complex to be explained on StackOverflow and it took us months to implement it. We called this feature widgets. See some demos here. As you can see there are no control selection when non-editable element is selected. The selection appears on a short moment only between mousedown and mouseup, but only in specific cases. Except for that everything works as it would be native (although it's a completely fake thing).
Read more in the Introduction to Widgets and in the Widgets Tutorial.
This post was critical when solving this issue for me (works in tinyMCE):
How to Remove Resize handles and border of div with contentEditable and size style
By placing a contenteditable DIV within a non contenteditable DIV the handles do not appear in IE or FF but you can still edit the content
Ex.
<div class="outerContainer" contenteditable="false">
<div class="innerContainer" contenteditable="true">
</div>
</div>
Solution 5
When the focus is moved to child control change the content editable element attribute value to false and same way once your focus leaves from child control again set the content editable to true.
To disable the resize handles, all I had to do was add the following for IE11:
div {
pointer-events: none;
}
For firefox executing this line after the contenteditable element has been inserted works:
document.execCommand("enableObjectResizing", false, false);
What solved the problem for me was removing a max-width: 100% !important; line from the CSS properties of the DOM elements within the contenteditable DIV. Hope it helps!
BTW this does not happen on MS Edge... fingers crossed that this shows a movement in the right direction by MS :)
I had the same problem. It appears that from previous posts here there are certain behaviors that IE recognizes and will add this paragraph focus/resize. For me it was because I had a style for paragraphs within the contenteditible div.
Removing:
div[contenteditble="true"] p{
min-height:1em;
}
Fixed it for me.
SOLVED!
On placing the non content-editable span within a content-editable BODY, it started showing a resize-able SPAN container. What just fix my problem was a simple one-liner CSS style
pointer-events: none; on the inner SPAN tag.
min-width: 1.5cm;
display: inline-block;
pointer-events: none;
<body content-editable="true">
<span>Sample Text</span>
</body>
overflow:hidden also can cause this issue, like:
ul, ol {
overflow: hidden;
}
I have the same problem with CKEditor 4.4.7 in IE11. As a workaround, I save the current dimensions of an element on "mousedown" and set the "min-width", "max-width", "min-height" and "max-height" style properties to it's current dimensions. By that the element will be displayed in it's original size during resize. On "mouseup" I restore the style properties of the modified element. Here is my code:
$('textarea').ckeditor().on('instanceReady.ckeditor', function(event, editor) {
var $doc = $(editor.document.$);
$doc.on("mousedown", "table,img", function() {
var $this = $(this);
var widthAttrValue = $this.attr("width");
if (widthAttrValue) {
$this.data("widthAttrValue", widthAttrValue);
}
var widthStyleValue = this.style.width;
if (widthStyleValue) {
$this.data("widthStyleValue", widthStyleValue);
}
var width = widthStyleValue || widthAttrValue || String($this.width())+"px";
var height = this.style.height || $this.attr("height") || String($this.height())+"px";
$this.css({
"min-width": width,
"max-width": width,
"min-height": height,
"max-height": height,
});
$doc.data("mouseDownElem",$this);
}).on("mouseup", function() {
var $elem = $doc.data("mouseDownElem");
if ($elem) {
$elem.removeAttr("height").css("height","");
var widthAttrValue = $elem.data("widthAttrValue");
if (widthAttrValue) {
$elem.attr("width", widthAttrValue);
$elem.removeData("widthAttrValue");
} else {
$elem.removeAttr("width");
}
var widthStyleValue = $elem.data("widthStyleValue");
if (widthStyleValue) {
$elem.removeData("widthStyleValue");
}
$elem.css({
"min-width":"",
"max-width":"",
"min-height":"",
"max-height":"",
"width": widthStyleValue || ""
});
if (!$.trim($elem.attr("style"))) {
$elem.removeAttr("style");
}
$doc.removeData("mouseDownElem");
}
});
});
Here's what I did to fix this problem. For me this would only happen when the contenteditable element was empty and the resize handles would disappear when there was content so I created the following CSS only solution to go about this:
[contenteditable]:empty:after {
content: " ";
}
The idea behind the solution is whenever the contenteditable field is empty it applies a blank space pseudo element thus removing the resize tags from showing up when the user selects the contenteditable field. Once the user has entered anything then the pseudo element disappears.
Note, because of the use of pseudo elements, this fix only works on IE9 and up.
I had the same problem because I put CSS rules for the max-width onto all child elements within the contenteditable. Removing it or restricting it to images did the trick.
[contenteditable] * { max-width: 100%; } // causes the issue
[contenteditable] img { max-width: 100%; } // works fine for me
Make sure that no <p> elements are affected by the max-width property.
Nothing anyone else recommended here or in other threads really worked for me, but I solved it by doing:
[contenteditable="true"] p:empty {
display: inline-block;
}
This way the resize boxes disappeared, but I could still set my cursor below or in the P blocks to edit them.
Related
When hovering over an element and then refreshing the page (without moving the mouse):
Chrome does not fire the mouseenter event on page load
Firefox does fire the mouseenter event on page load
Below is an example snippet. To reproduce the issue, hover over the div and then refresh the page. In Chrome, the div does not contain "mouseenter". In Firefox, it does.
Note that this does not work in the Stacksnippets environment since you need to click "run snippet" first. JSFiddle: https://jsfiddle.net/9fu6cx5d/7/
let div = document.getElementById('my-div');
div.addEventListener('mouseenter', function () {
div.innerHTML = 'mouseenter';
});
#my-div {
width: 150px;
height: 150px;
background-color: #aaaaaa;
}
<div id="my-div">
</div>
Which browser has the correct behaviour? How can I work around the difference in behaviour or at least make them both behave the same?
Chrome version: 59.0.3071.115 (Official Build) (64-bit)
Firefox version: 54.0 (64-bit)
As pointed out in the comments, Chrome's behavior is the correct one according to the specs. Below is an idea on how to work around the difference.
You can make sure you get the value right by checking whether the mouse is inside the bounds of the div on document load. Unfortunately there is no way in JS to check the mouse position without firing events, so you will have to resort to some hack involving CSS hover rules and checking against them on $(document).ready.
To quote this hilarious answer:
Overlay your page with a div that covers the whole document. Inside
that, create (say) 2,000 x 2,000 elements (so that the :hover
pseudo-class will work in IE 6, see), each 1 pixel in size. Create a
CSS :hover rule for those elements that changes a property (let's
say font-family). In your load handler, cycle through each of the 4
million elements, checking currentStyle / getComputedStyle() until
you find the one with the hover font. Extrapolate back from this
element to get the co-ordinates within the document.
N.B. DON'T DO THIS.
While you definitely shouldn't do this, the general idea of using non-effective hover styles for the sake of checking if an element is hovered without needing JS events is a good one if you just need to work around browser quirks. I'm using font-weight in the example below, but you can change it to whatever works for you.
The css
#my-div:hover {font-weight:700;}
The js
// Pseudocode!
var mouseIsInside = false,
div = $('#my-div');
$(document).ready(function(){
if (div.css('font-weight') === 700) {
mouseIsInside = true;
}
doStuffIfMouseInside();
});
div.on('mouseenter', function(){
mouseIsInside = true;
doStuffIfMouseInside();
})
function doStuffIfMouseInside() {
if (mouseIsInside) {
...
}
}
If you add (function(){})(); around your code it seems to work in both browsers.
It seems that firefox might be firing events before the dom is available causing problems with mousein/out events.
See: https://jsfiddle.net/9fu6cx5d/8/
I'm around trying to remove a DOM element (I'll put it elsewhere) and I need the position of the sibling elements do not change.
I tried some variations of this.
var elem = $("#theElement");
var ghost = $('<div></div>');
ghost.css({
width: elem.outerWidth(true),
height: elem.outerHeight(true),
margin: 0
});
elem.replaceWith(ghost);
But the document collapses slightly.
I know I can just change the visibility of the element, but not what I need. I'll put it somewhere else in the DOM and can not be duplicated.
The Question
How to replace any kind of element with a div that occupies the same space?
EDIT
Keep in mind that i can not change the source element attributes.
I do not know in advance which item and which properties it has, just take it out of where it is and move it elsewhere.
The jQuery documentation says:
.outerHeight(true): if the includeMargin argument is set to true, the margin (top and bottom) is also included.
.outerWidth(true): If includeMargin is omitted or false, the padding and border are included in the calculation; if true, the margin is also included.
plunker
That is because of the margin given by the browser, called user agent stylesheet in dev tools.
I have modified your plunk to have css like this
h1 {
color: red;
margin:0px !important;
}
Issue seemed to be resolved.
EDIT:
I have edited your code to be something like this:
$(function(){
var elem = $("h1");
var ghost = $('<div></div>');
ghost.css({
width: elem.outerWidth(),
height: elem.outerHeight(),
margin: 21
});
Since you can not modify the source, identify what styling the browser is putting onto it and give your ghost element the same styling.
To detect what css the browser is putting onto your element, refer
http://www.iecss.com
http://mxr.mozilla.org/mozilla-central/source/layout/style/html.css
http://trac.webkit.org/browser/trunk/Source/WebCore/css/html.css
I am currently using display:none to hide all the divs on my website. Users click on like for example "info" or "contact" and the appropriate div will slide down via JQuery. To support users without Javascript, the links goes to "info.php" and "contact.php" if Javascript is no enabled.
This is quite a hassle to maintain because I have to update both the main page and the non-javascript versions (info.php, contact.php etc) when I make any changes.
What is a sensible back up to JQuery sliding divs for users without Javascript?
When I have understood you right, make a php-file with the static content. (The content on all sites) und include the content (info/contact) per include from another file depending on a GET Param like "page".
Hide the <div>s with jQuery so that users without JavaScript can still see all the <div>s in one long page. Users with JavaScript, on the other hand, can slide the <div>s as usual.
jQuery IS JavaScript - is cannot be a backup plan.
one does not simply use the terms JavaScript and jQuery interchangeably
jQuery is a JavaScript library. By disabling JavaScript, the jQuery scripts will not be able to hide the <div>s. The key is to keep it functional when JavaScript is not available. As long as you do not perform critical manipulation to the page that would render it non-functional without JavaScript, you can cater for those non-JavaScript users. In this case, putting the modification work over to jQuery (or JavaScript) is a way to preserve functionality.
At first add a class to_hide to all divs which should be hidden when javascript is activated.
The simplest way is to hide the divs like this on page load:
$(document).ready(function() {
$('.to_hide').hide();
});
Note that if you do this, the layout will blink when loaded (the full content will be shown at first and then the dynamic divs will be hidden).
To avoid blinking you can add css rule for to_hide class dynamically. Use the following function in the <head> to do that:
function dyn_css_rule(sSelector, sCssText) {
try {
var aSS = document.styleSheets;
var i;
for (i=aSS.length-1; i>=0; i--) {
var oCss = document.styleSheets[i];
var sMedia = (typeof(oCss.media) == "string")?
oCss.media:
oCss.media.mediaText;
if (!sMedia
|| sMedia.indexOf("screen") != -1
|| sMedia.indexOf("all") != -1
) {
break;
}
}
if (oCss.insertRule) {
oCss.insertRule(sSelector + " {" + sCssText + "}", oCss.cssRules.length);
} else if (oCss.addRule) {
oCss.addRule(sSelector, sCssText);
}
} catch(err) {
var tag = document.createElement('style');
tag.type = 'text/css';
try {
tag.innerHTML = sSelector + " {" + sCssText + "}";
} catch(err) {
tag.innerText = sSelector + " {" + sCssText + "}";
}
document.getElementsByTagName('head')[0].appendChild(tag);
}
return sSelector + "{" + sCssText + "}";
};
dyn_css_rule('.to_hide', 'display: none');
A Pure CSS Solution
This may or may not work depending on the situation, but you can actually mimic a drop-down menu's behavior with css selectors in IE8 and up. Here's an example. Click on the menu, and as long as you hover around the content the content will appear, no javascript required.
Functionality
By default, all the content is hidden. However, thanks to the :active pseudoclass, you can change the content to display when the parent is clicked. This is pretty inconvenient though - the user has to hold down the mouse to see anything. However, we can cheat a bit - by adding a :hover pseudoclass that displays the content, if the user clicks and hovers the content will stick around.
So far, we have this css:
.container.content {
display: none;
}
.container:active .content {
display: block;
}
.content:hover {
display: block;
}
This is a little flaky though - you have to move your mouse down over the content to have it persist, and will likely confuse. We can cheat a bit though by making the content larger than it appears. A simple way to do this would to be just to padding (that's what I've done in the example I added), but this can cause some odd reflow issues. A better way I think is to add deliberate spacing divs that add to the size of the content without changing the flow.
If we add this
<div style="position:absolute; top:-50px; height: 50px; width: 100%;"></div>
to the start of the content, there's an invisible div hovering over the menu, which will extend the area on which hover works. A similar thing can be done to the bottom, leaving us with a solution that has a larger hover area, and doesn't trigger reflows beyond the main content.
Remaining Problems
Anyway, this isn't perfect since it certainly isn't as flexible as javascript. There's no sliding, and you can't reliably make the content show up if the user mouses out.
As other people suggested, you can still improve this with javascript after the fact should the user have it enabled though - this can still work as a decent backup to noscript users.
I ended up using a solution that combines Antony's answer and this answer: https://stackoverflow.com/a/8928909/1342461
<html class="no-js">
<body>
<div id="foo"></div>
</body>
</html>
#foo
{
display: none;
}
html.no-js #foo
{
display: block;
}
$(document).ready(
function()
{
$('html').removeClass('no-js');
}
);
All the divs will be seen by people without javascript. Then, I can set my navigation links to a href="#info" for example, to get it to scroll down to the correct div for non-javascript users while doing "slide.down()" etc for javascript users.
Have your info.php main text in an include file. Lets say info.inc.php
When non-js user clicks the link, they go to info.php into which the include file is, well, included.
But when a js user clicks the link, you load the info.inc.php onto your div and only THEN show it with jquery.
Say
$('a.info').click(function(e){
e.preventDefault();
$('#infoDiv').load('info.inc.php')
.show();
return false;
});
When you need to update content, just update the include file.
I'm building an auto-follow div that is bound to the $(window).scroll() event. Here is my JavaScript.
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"));
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if(scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2))+"px");
console.log("Setting margin-top to "+$("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
This code assumes that there is this CSS rule in place
#ActionBox {
margin-top: 15px;
}
And it takes an element with the id "ActionBox" (in this case a div). The div is positioned in a left aligned menu that runs down the side, so it's starting offset is approximately 200 px). The goal is to start adding to the margin-top value once the user has scrolled past the point where the div might start to disappear off the top of the browser viewport (yes I know setting it to position: fixed would do the same thing, but then it would obscure the content below the ActionBox but still in the menu).
Now the console.log shows that the event is firing every time it should and it's setting the correct value. But in some pages of my web app the div isn't redrawn. This is especially odd because in other pages (in IE) the code works as expected (and it works every time in FF, Opera and WebKit). All pages evaluate (0 errors and 0 warnings according to the W3C validator and the FireFox HTMLTidy Validator), and no JS errors are thrown (according to the IE Developer Toolbar and Firebug). One other part to this mystery, if I unselect the #ActionBox margin-top rule in the HTML Style explorer in the IE Developer Tools then the div jumps immediately back in the newly adjusted place that it should have if the scroll event had triggered a redraw. Also if I force IE8 into Quirks Mode or compatibility mode then the even triggers an update.
One More thing, it works as expected in IE7 and IE 6 (thanks to the wonderful IETester for that)
I'm having a problem with your script in Firefox. When I scroll down, the script continues to add a margin to the page and I never reach the bottom of the page. This occurs because the ActionBox is still part of the page elements. I posted a demo here.
One solution would be to add a position: fixed to the CSS definition, but I see this won't work for you
Another solution would be to position the ActionBox absolutely (to the document body) and adjust the top.
Updated the code to fit with the solution found for others to benefit.
UPDATED:
CSS
#ActionBox {
position: relative;
float: right;
}
Script
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"),10);
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if (scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2)) + "px");
console.log("Setting margin-top to " + $("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
Also it is important to add a base (10 in this case) to your parseInt(), e.g.
parseInt($("#ActionBox").css("top"),10);
Try marginTop in place of margin-top, eg:
$("#ActionBox").css("marginTop", foo);
I found the answer!
I want to acknowledge the hard work of everyone in trying to find a better way to solve this problem, unfortunately because of a series of larger constraints I am unable to select them as the "answer" (I am voting them up because you deserve points for contributing).
The specific problem I was facing was a JavaScript onScoll event that was firing but a subsequent CSS update that wasn't causing IE8 (in standards mode) to redraw. Even stranger was the fact that in some pages it was redrawing while in others (with no obvious similarity) it wasn't. The solution in the end was to add the following CSS
#ActionBox {
position: relative;
float: right;
}
Here is an updated pastbin showing this (I added some more style to show how I am implementing this code). The IE "edit code" then "view output" bug fudgey talked about still occurs (but it seems to be a event binding issue unique to pastbin (and similar services)
I don't know why adding "float: right" allows IE8 to complete a redraw on an event that was already firing, but for some reason it does.
The correct format for IE8 is:
$("#ActionBox").css({ 'margin-top': '10px' });
with this work.
try this method
$("your id or class name").css({ 'margin-top': '18px' });
I'm currently extending the lavalamp plugin to work on dropdown menus but I've encountered a small problem. I need to know the offsetWidth of an element that is hidden. Now clearly this question makes no sense, rather what I'm looking for is the offsetWidth of the element were it not hidden.
Is the solution to show it, grab the width, then hide again? There must be a better way...
The width of an element that has CSS visibility: hidden is measurable. It's only when it's display: none that it's not rendered at all. So if it's certain the elements are going to be absolutely-positioned (so they don't cause a layout change when displayed), simply use css('visibility', 'hidden') to hide your element instead of hide() and you should be OK measuring the width.
Otherwise, yes, show-measure-hide does work.
The only thing I can think of is to show it (or a clone of it) to allow retrieval of the offsetWidth.
For this measurement step, just make its position absolute and its x or y value a big negative, so it will render but not be visible to the user.
You can use the following function to get the outer width of an element that is inside a hidden container.
$.fn.getHiddenOffsetWidth = function () {
// save a reference to a cloned element that can be measured
var $hiddenElement = $(this).clone().appendTo('body');
// calculate the width of the clone
var width = $hiddenElement.outerWidth();
// remove the clone from the DOM
$hiddenElement.remove();
return width;
};
You can change .outerWidth() to .offsetWidth() for your situation.
The function first clones the element, copying it to a place where it will be visible. It then retrieves the offset width and finally removes the clone. The following snippet illustrates a situation where this function would be perfect:
<style>
.container-inner {
display: none;
}
.measure-me {
width: 120px;
}
</style>
<div class="container-outer">
<div class="container-inner">
<div class="measure-me"></div>
</div>
</div>
Please be aware that if there is CSS applied to the element that changes the width of the element that won't be applied if it's a direct descendant of body, then this method won't work. So something like this will mean that the function doesn't work:
.container-outer .measure-me {
width: 100px;
}
You'll either need to:
change the specificity of the CSS selector ie. .measure-me { width: 100px; }
change the appendTo() to add the clone to a place where your CSS will also be applied to the clone. Ensure that where ever you do put it, that the element will be visible: .appendTo('.container-outer')
Again, this function assumes that the element is only hidden because it's inside a hidden container. If the element itself is display:none, you can simply add some code to make the clone visible before you retrieve it's offset width. Something like this:
$.fn.getHiddenOffsetWidth = function () {
var hiddenElement $(this)
width = 0;
// make the element measurable
hiddenElement.show();
// calculate the width of the element
width = hiddenElement.outerWidth();
// hide the element again
hiddenElement.hide();
return width;
}
This would work in a situation like this:
<style>
.measure-me {
display: none;
width: 120px;
}
</style>
<div class="container">
<div class="measure-me"></div>
</div>
Two options:
position the element outside the viewport (ex: left:-10000px)
use visibility: hidden or opacity: 0 instead of hide().
Either way will work as hiding the element but still being able to get the computed width. Be careful with Safari on thi, it's awfully fast and sometimes too fast...
Actual jQuery plugin!
Usage:
console.log('width without actual: ' + $('#hidden').width());
console.log('width with actual: ' + $('#hidden').actual('width'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.actual/1.0.19/jquery.actual.min.js"></script>
<div style="width: 100px; display: none;">
<div id="hidden"></div>
</div>
If you know the element to be the full width of a parent element another approach is to create a recursive method:
es5:
var getWidth;
getWidth = function($el){
return $el.offsetWidth || getWidth($el.parentElement);
}
var width = getWidth(document.getElementById('the-element'));
es6:
let getWidth
getWidth = ($el) => $el.offsetWidth || getWidth($el.parentElement)
const width = getWidth(document.getElementById('the-element'))
What I did was ;
by the time hiding that element, stored its width in its dataset.
It only will work for you if you can hide programmatically.
ie.
When Hiding ;
var elem = $("selectorOfElement");
elem.dataset.orgWidth = elem.clientWidth;
Later when getting ;
var elem = $("selectorOfElement");
var originalWidthWas = elem.dataset.orgWidth;
thats because its hidden via display: none; What ive done in the past is to make a "reciever" div which i use absolute positioning on to get it off the page. Then i load the new element into that, grab the dimensions and then remove it when im done - then remove the reciever when im done.
Another thing you can do is to not use hide(); but to instead set visibility: hidden; display: ; However this means the blank area will be rendered wherever the node is attached.
var $hiddenElement = $('#id_of_your_item').clone().css({ left: -10000, top: -10000, position: 'absolute', display: 'inline', visibility: 'visible' }).appendTo('body');
var width = parseInt($hiddenElement.outerWidth());
$hiddenElement.remove();
I try to find working function for hidden element but I realize that CSS is much complex than everyone think. There are a lot of new layout techniques in CSS3 that might not work for all previous answers like flexible box, grid, column or even element inside complex parent element.
flexibox example
I think the only sustainable & simple solution is real-time rendering. At that time, browser should give you that correct element size.
Sadly, JavaScript does not provide any direct event to notify when element is showed or hidden. However, I create some function based on DOM Attribute Modified API that will execute callback function when visibility of element is changed.
$('[selector]').onVisibleChanged(function(e, isVisible)
{
var realWidth = $('[selector]').width();
var realHeight = $('[selector]').height();
// render or adjust something
});
For more information, Please visit at my project GitHub.
https://github.com/Soul-Master/visible.event.js
demo: http://jsbin.com/ETiGIre/7
Sorry I am late to this conversation. I am surprised no one has mentioned getComputedStyle. (Note this only works if the CSS sets a width value)
Grab the element:
let yourEle = document.getElementById('this-ele-id');
and use the function:
getComputedStyle(yourEle).width
This returns a string so you will have to remove the numbers from the string.
This works even when the element's display style is set to none.
Other articles to read about this includes here at zellwk.com