Tuesday, March 28, 2006

Max-width in IE Using a CSS Expression

This post is a continuation of the "How Many Pixels in an EM?" series I have been working on, although now that I know exactly how to calculate the number of pixels in an em, I've moved on to refining other aspects of the expression itself, and so I've decided to move away from that title.

I contacted Svend Tofte himself regarding this work, and he took time away from his very busy schedule to give me some very valuable feedback (many thanks to Svend!). He pointed out to me that expressions that may work well in quirks mode can cause the browser to crash in strict mode, due to differences in the box model than can trigger infinite loops.

As I am no stranger to danger, I slapped a strict doctype on my test page and... voila... brought my mighty workstation to its knees. CTRL-ALT-DELETE did nothing. I actually had to manually switch off the box for the first time ever.

As soon as I could power back up, I removed all margins, padding, and borders from my test elements, loaded the page, and started resizing my browser like a madman. The divs scaled perfectly this time... No locked-up IE, no smoke coming off my CPU, just good old-fashioned max-width joy.

To make this long story short (or at least a reasonable length) I did some investigating and found that you have to factor in the total width of your margins, padding, and borders in order to use the expression safely in strict mode. Since you're testing the offsetWidth and then setting the CSS width property, you have to compensate for the differences between the two. Otherwise, it is possible for the expression to enter an infinite loop where setting the width of the element causes the parent element to change its size, which again fires the expression, and so on.

Without further adieu, here is the expression in all its hairy glory:

width:expression((this.parentElement.offsetWidth - (parseInt(this.parentElement.currentStyle.paddingLeft)+parseInt(this.parentElement.currentStyle.paddingRight)+parseInt(this.parentElement.currentStyle.borderLeftWidth)+parseInt(this.parentElement.currentStyle.borderRightWidth)))
> ( Math.round((30*(screen.deviceXDPI?screen.deviceXDPI:96)/72)*parseInt(document.body.currentStyle.fontSize)) + (parseInt(this.currentStyle.marginLeft)+parseInt(this.currentStyle.marginRight)+parseInt(this.currentStyle.paddingLeft)+parseInt(this.currentStyle.paddingRight)+parseInt(this.currentStyle.borderLeftWidth)+parseInt(this.currentStyle.borderRightWidth)))
? "30em":"auto");
Quite a beast, no? Pretty it's not, but it works really well in strict mode, in IE 5, 5.5, and 6. With any combination of margins, borders, and padding you care to throw at it, and at any screen resolution. Don't believe me? Take a look at my test page.

There are two places where you have to specify the desired max-width. Just replace the number 30 with the number of your choosing. You can also replace "auto" with another value, but I would be very careful when doing so. If that value should somehow evaluate to greater than your max-width value, I would expect to start seeing flames shooting out of your USB ports. ;) (ok, so maybe I'm being dramatic).

I'll be testing variations on this expression in the near future, so stop back and check out my progress. Also, please check out the test page and let me know how it works for you!

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

30 Comments:

Anonymous Anonymous said...

Truly terrifying.

Any idea how to do max-*height* in IE like this? I've put a lot of braincycles into it, and haven't come up with an answer--nor has anyone else, AFAIK.

Thanks

10:27 AM  
Blogger tom said...

Yeah, that's a tricky one. Haven't had time to fully investigate it, but I'll be getting to it sometime soon.

The thing with these long CSS expressions is that you can put them into a JavaScript function instead, and just call the function from your CSS expression. Much tidier, and since CSS expressions don't work with scripting turned off, you're not losing browser share.

I would eventually like to create a CSSHelpers JavaScript library which would include min-width, max-width, min-height, and max-height as well as some other useful stuff.

11:41 AM  
Anonymous Anonymous said...

Hi

Is it just me or are expressions REALLY SLOW.

for example, i've got this nested condition in an expression, and its as soon as you have more than one property like this it gets really slow on large tables (e.g. a datagrid in a scrolling div with 50 rows or more)

E.G.
background-color : expression(
(this.type=="submit" || this.type=="button") ?'89A2B3':
(this.type=="text") ?'white':
(this.type=="checkbox") ?'':
'white'
);



Any idea on how to get these damn things to be quicker!!!!!

8:37 AM  
Blogger tom said...

One of the downsides of expressions is that they are evaluated extremely frequently, and so they're not well suited to every circumstance. They execute when the mouse is moved over the targeted element, or when the browser is resized. Other events may also trigger them. One thing that may be slowing down your expression is the fact that the color is being set regardless of whether or not it needs to be. If it has been set once, it doesn't need to be set again. I would first check to see if the background-color property has been set yet: if it has, use "delete this;" to stop the expression from executing again. Here's an example of what I mean: http://labs.tom-lee.com/CSS/Expressions/BgColor.html. Hope that helps!

5:34 PM  
Anonymous Anonymous said...

Thanks for the tip. I gave it try and does speed up the response when interacting with the page. However, a new problem has now arisen.

First let me explain the big picture.

I am trying to use dynamic expression to create a corporate standard stylesheet that will work nicely with DotNet.

The Idea is to use dynamic expressions to format various elements without having to actually sent the class manually. So I check the type of control (based on what Asp.Net web control will render as), and then apply various formatting (e.g. color, font, size, borders etc).

Now this works great on smaller pages, but you really start noticing the performance when theres alot of controls/elements.

The solution you suggested seems to work for speeding up working on the page, but now the page takes REALLY long to display, and I guess its the script thats formatting the controls thats so slow.

Is this a futile effort? Should we just go back to manually setting the class attribute?

Thanks again for your help.

2:16 AM  
Blogger tom said...

Going by the code you posted, there's some room for optimization, although I'm not sure how far it will get you. I would suggest this:

background-color : expression(
(this.type=="submit" || this.type=="button") ?'89A2B3':
(this.type=="checkbox") ?'transparent':
'white'
);

This expression does fewer conditional checks so it will execute a little faster. Also, it looks like you were setting the checkbox background to an empty string, which I don't believe is a correct value. Would be better to use 'transparent' instead.

Let me know if that helps!

7:24 AM  
Anonymous Anonymous said...

For the dot net developer - every heard of skins?

10:50 AM  
Anonymous Anonymous said...

I've been testing this max-width css expression, and having a hard time with it. It works great in your example, because your example is very simple. For instance, for a small browser window (800x600) or for a large (1280x1024), the max-width css expression seems to work fine, but somewhere in the middle it is bugging out on me! I wish somebody could look at this code and tell me what I'm doing or not doing!

2:32 PM  
Blogger tom said...

Leave a comment with a URL to your page, and I'll be glad to take a look when I get a chance.

5:51 PM  
Anonymous Anonymous said...

hey tom, thanks for this - i've been pulling my hair out on this for sometime.

the one thing I'm seeing, is that I have an image in the same div as the text that is being adjusted, and because of this, once the text box gets smaller than the image, the whole div "float drops" past the left column I have positioned via float.

Usually, setting overflow to auto or the like will fix it, but I think this expression is over writing other css like that.

check out http://www.gothamistllc.com/glob in IE to see what I mean by it dropping. Of course, if you look at it at any other modern browser, like FF or Safari, you can see the desired effect.

Thanks for your time!

9:18 PM  
Blogger tom said...

Hi Neil,

This looks to me like a standard-issue float drop. I checked out your page in IE6 and Firefox 1.0 - while Firefox doesn't have the float drop, you can still see the horizontal scrollbar at the bottom of the browser. That indicates something is pushing out the width of your main div. Looking at it in IE, I can see some horizontal rules which don't seem to be scaling down with the rest of the content: could that be the issue? Here's an FAQ on float drops and their possible causes: http://www.sitepoint.com/forums/showpost.php?p=1374925&postcount=15. Hope that helps!!

7:08 AM  
Anonymous Anonymous said...

I found a problem with this solution. It appears when the border width is "medium" the parseInt() returns NaN and the system breaks.

In my experiment, borders for div were set to medium by default and the borders were not visible. One can bypass this problem by setting border width for div to 0 or to another number value;

3:31 AM  
Anonymous Anonymous said...

Oh, you need to set the border width on the parent element too to a number value to avoid the problem. I do not know if there's a way to figure out how much is 'medium' in px value.

3:34 AM  
Blogger tom said...

I should have pointed out that since we're just using parseInt on the borderWidth property, the expression assumes that border widths are specified in pixels. If you want to use something other than pixels for the border widths, you'll need to modify the expression to convert the widths to pixels. If you're using relative units for your border widths, it gets quite complicated to perform the conversion. These kinds of things are what makes a one-size-fits-all solution very difficult to create.

7:04 PM  
Anonymous Anonymous said...

tom, I have a strange case about your example in http://labs.tom-lee.com/CSS/Expressions/BgColor.html

if I change the div into a text input element, then a error will throw on 'delete this'

do you know the reason?

10:29 PM  
Blogger Lighthouse said...

Tom
Thank you for sharing that:

Another way is to set individually as needed, for clarity's sake

Use this on any element or class definition:

(equivalent of max-width:160px that can be set with it for non-IE compatibility)

width:expression(Math.min(parseInt(this.offsetWidth), 160 ) + "px");

Peter

1:51 PM  
Blogger tom said...

Peter,

While your solution definitely has greater clarity, it will not be as fault-tolerant. If you're not careful, these expressions can lock up a system to the point of a forced reboot. That's why it was necessary to make such a lengthy expression. See the details in the original post for more.

-tom

6:57 PM  
Blogger tom said...

Victor,

Sorry - I don't know why that could be happening. Maybe you can wrap the text area in a div and apply max-width to that?

-tom

7:03 PM  
Blogger Lighthouse said...

Thanks Tom
me was thinking here's a comment to an old post that he's sure to miss :-|)

I must admit I haven't used it on that many element definitions at a go, but I can see your point

Incidentally, don't know if you covered it but the svend tofte solution
http://www.svendtofte.com/code/max_width_in_ie/

max-width:800px;
width:expression(document.body.clientWidth > 800? "800px": "auto" );

does freeze things up very easily,
apparently due to a comparison
problem with equal numbers
so that say

width:expression(document.body.clientWidth > 799? "800px": "auto" );

should be used instead with that (single element) system

Peter

7:44 AM  
Anonymous Anonymous said...

Easiest way to stop IE6 from crashing and burning is to change the < expression to <= .. small thing .. but it works as shown : http://defunc.com/blog/?p=62

Some expressions just freeze up the browser so you have to be careful how they are written.

9:46 AM  
Blogger Femi said...

This is great for max width and works a treat! I'm looking to set min width and cant seem to adapt this. I have margins and paddings everywhere and have been crashimng IE on the declaring > x picxels way. Thanks anyways for the insight.

7:18 AM  
Anonymous Anonymous said...

搬家
搬家
搬家公司
徵信社
徵信
彩妝造型
新娘秘書
票貼
室內設計
室內設計
徵信
徵信社
外遇
徵信
徵信社
外遇
搬家
搬家
花蓮民宿
花蓮民宿
免費a片
a片
免費av
色情影片
情色
情色網
色情網站
色情
成人網
成人圖片
成人影片
18成人
av
av女優

情慾
走光
做愛
sex
H漫
免費a片
a片
免費av
色情影片
情色
情色網
色情網站
色情
成人網
成人圖片
成人影片
18成人
av
av女優

情慾
走光
做愛
sex
H漫
a片
アダルト
アダルト
アダルトサイト
アダルトサイト
離婚
抓姦
外遇蒐證
外遇抓姦
外遇
侵權
仿冒
應收帳款
工商徵信
Shade sail
nike shoes
水泵
电动隔膜泵
自吸泵
离心泵
磁力泵
螺杆泵
化工泵
水泵
电动隔膜泵
自吸泵
离心泵
磁力泵
螺杆泵
化工泵
水泵
电动隔膜泵
自吸泵
离心泵
磁力泵
螺杆泵
化工泵
隔膜泵
气动隔膜泵
隔膜泵
气动隔膜泵
隔膜泵
气动隔膜泵
a片
成人網站
成人影片
寵物用品
情趣用品
情趣用品
MBA
在职研究生
在职博士
補習班
花店
花店
補正下着
中古車買賣
貸款
婚紗
婚紗攝影
補習班
留學
情色
情色
百家乐
轮盘
21点
德州扑克
百家乐系统
真人娱乐场
百家乐
足球
德州扑克
电子游戏
英格兰超级联赛
德国甲组联赛
意大利甲组联赛
西班牙甲组联赛
法国甲组联赛欧冠杯
英超
足球比分
足球彩票
体育彩票
即时比分
堆高機
婚禮佈置
宜蘭民宿推薦
寵物用品
情趣用品
情趣用品
坐月子
植牙
牙齒矯正
租屋
催眠
房屋出租
租房子
xo醬
牛軋糖
牛嘎糖
代償
房屋貸款
信用貸款
失眠
減肥
眼鏡
金門高梁酒
變頻洗衣機


減肥
眼鏡
睡眠障礙
憂鬱症
躁鬱症
減重
瘦身
中醫減肥
台北中醫減肥
台中中醫減肥
高雄中醫減肥
產後減肥
下半身減肥
下半身瘦身
高雄眼鏡
屏東眼鏡
名牌眼鏡
太陽眼鏡
隱形眼鏡
鐵氟龍
PTFE
中壢花店
林口花店
南崁花店
金莎花束
歌倫比亞 雞腳凍
飲料加盟

太陽餅
月餅
口袋秤
度量衡
吊秤
吊磅
電子秤
磅秤
口袋秤
度量衡
吊秤
吊磅
電子秤
磅秤
招牌製作
招牌設計
廣告招牌
大圖輸出
電腦割字
招牌看板
廢鐵
廢銅
廢不銹鋼
廢電線
廢鋁
廢棄物
廢電纜電線
廢塑膠
制服
成衣
戒指
耳環
項鍊
對戒
手鍊
銀飾
飾品
對鍊
護理之家
台中花店
考試
塑膠箱
塑膠容器
工具箱
物流箱
拖板車
自動倉儲
倉儲設備
自行車衣
自行車背包
自行車手套
車衣
債務更生
債務清理
法協
蜂蜜
蜂王乳花粉
農產品
草本膠囊
促進新陳代謝
排便順暢的方法
體內環保
塑膠射出
塑膠製品
塑膠箱籃
物流塑膠箱
休閒傢俱
庭園圍籬

7:24 PM  
Anonymous Anonymous said...

好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結
好站推薦友情連結 aa片免費看微風論壇080哈啦聊天室6k聊天室成人聊天室上班族捷克論壇大眾論壇plus論壇080視訊聊天室520視訊聊天室尋夢園上班族聊天室成人聊天室上班族 a片a片影片免費情色影片免費a片觀看小弟第貼影片區免費av影片免費h影片試看 H漫 - 卡通美女短片小魔女貼影片免費影片觀賞無碼a片網美女pc交友相簿美女交友-哈啦聊天室中文a片線上試看免費電影下載區免費試看a短片免費卡通aa片觀看女優影片無碼直播免費性感a片試看日本AV女優影音娛樂網日本av女優無碼 dvd辣妹視訊 - 免費聊天室美女交友視訊聊天室 080免費視訊聊天室尋夢園聊天室080苗栗人聊天室a片下載

5:36 PM  
Anonymous Anonymous said...

威創牙醫診所除了提供優質的植牙技術外還提供假牙|矯正|牙周病治療,是值得您信賴的牙醫診所

獅王紋身工作室提供專業的無痛刺青技術,獅王紋身在世界TATTOO大賽中,獲獎無數,獅王紋身給您最時尚的作品。

陳駿逸皮膚科診所提供了治療痘痘的服務,皮膚雷射權威,包括雷射脈衝光除斑等,讓您回復青春蘋果臉。

ck皮件處理棧提供專業洗包包|洗鞋子|各式皮件修理保養疑難雜症都有服務,清洗包包專門店讓您的包包、鞋子、永遠保持最新的況態唷。

杏儒中醫診所提供了糖尿病的治療。

7:00 AM  
Anonymous Anonymous said...

專業合法驅除
白蟻
除白蟻
白蟻防治
跳蚤
除跳蚤
跳蚤防治
蛀蟲
除蛀蟲
蛀蟲防治
白蟻
除白蟻
白蟻防治
跳蚤
除跳蚤
跳蚤防治
蛀蟲
除蛀蟲
蛀蟲防治
除蟲
除蟲
歡迎參閱

8:16 AM  
Blogger 說妳美美美睫美甲紋繡預約0915551807 said...

This comment has been removed by the author.

9:18 AM  
Anonymous Anonymous said...

情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣商品,情趣商品,情趣商品,情趣商品,情趣商品,情趣商品,情趣商品,情趣商品,香蕉按摩棒..情趣用品...香蕉情趣用品..情人節..情趣浪漫..情趣同志..情趣..情趣商品.情趣內衣..成人用品..男同志..女同志..按摩棒,女同按摩棒,,自慰,自衛套,情趣用品,跳蛋,plus28,情趣交友,潤滑液,情趣睡衣,口交,情趣加盟,情趣內睡衣,香蕉性樂園,按摩棒,AV女優,情趣知識,香蕉性樂園,交友聊天室,
情趣,情趣Motel,A片女優,貴婦熟女,找女朋友,日本Tenga,杜蕾絲,香蕉樂園,小巧按摩棒,情趣加盟,性用舖,美女老師,聊天視訊,情趣用具,情趣夜店,情趣用品,情趣香蕉,大亨情趣達人,夜貓子的最愛,DUREX,69的奇妙,成人用品

11:11 AM  
Blogger 說妳美美美睫美甲紋繡預約0915551807 said...

This comment has been removed by the author.

8:42 AM  
Blogger 說妳美美美睫美甲紋繡預約0915551807 said...

This comment has been removed by the author.

12:11 AM  
Blogger 說妳美美美睫美甲紋繡預約0915551807 said...

This comment has been removed by the author.

7:05 AM  

Post a Comment

<< Home