I have a UIWebView
with different (single page) content. I'd like to find out the CGSize
of the content to resize my parent views appropriately. The obvious -sizeThatFits:
unfortunately just returns the current frame size of the webView.

- 52,648
- 24
- 135
- 213
-
1I'm not sure, but perhaps the answers to this question will help: http://stackoverflow.com/questions/745160/how-to-determine-uiwebview-height-based-on-content-within-a-variable-height-uita – Greg Oct 14 '10 at 17:56
15 Answers
It turned out that my first guess using -sizeThatFits:
was not completely wrong. It seems to work, but only if the frame of the webView is set to a minimal size prior to sending -sizeThatFits:
. After that we can correct the wrong frame size by the fitting size. This sounds terrible but it's actually not that bad. Since we do both frame changes right after each other, the view isn't updated and doesn't flicker.
Of course, we have to wait until the content has been loaded, so we put the code into the -webViewDidFinishLoad:
delegate method.
Obj-C
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
CGRect frame = aWebView.frame;
frame.size.height = 1;
aWebView.frame = frame;
CGSize fittingSize = [aWebView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
aWebView.frame = frame;
NSLog(@"size: %f, %f", fittingSize.width, fittingSize.height);
}
Swift 4.x
func webViewDidFinishLoad(_ webView: UIWebView) {
var frame = webView.frame
frame.size.height = 1
webView.frame = frame
let fittingSize = webView.sizeThatFits(CGSize.init(width: 0, height: 0))
frame.size = fittingSize
webView.frame = frame
}
I should point out there's another approach (thanks @GregInYEG) using JavaScript. Not sure which solution performs better.
Of two hacky solutions I like this one better.

- 2,241
- 1
- 22
- 27

- 52,648
- 24
- 135
- 213
-
I tried your approach. The problem I experienced is that there is no scrolling. Any suggestions? – testing Dec 11 '10 at 15:31
-
1I found out that the problem with the scrolling occurs because of the changed webview height. Do I have to change the UIView sizes? – testing Dec 11 '10 at 16:54
-
Not sure what your problem is. Perhaps you can post a new question with some code or description? – Ortwin Gentz Dec 11 '10 at 23:52
-
@testing, @Bogatyr: Right, if your `UIWebView` is higher than your parent view, you need to embed it into a `UIScrollView`. – Ortwin Gentz Apr 06 '11 at 11:41
-
7if am giving webView.scalesPageToFit = YES; then only this solution works..thanks for the solution.. – S.P. May 03 '11 at 09:13
-
As said in my own post, it works only on iOS 6. Implementing it under iOS 5 will fail. – Phenomena Nov 29 '12 at 21:11
-
Phenomena, as you can deduce from the date of the post, the solution of course works with older iOS versions, at least back to 4.0. What problems did you experience? – Ortwin Gentz Nov 29 '12 at 21:59
-
It gave incorrect size when used with some kind of HTML pages that were including many items. I noticed that the computed height was usually smaller than the actual size needed to display the whole page. – Phenomena Dec 05 '12 at 00:26
-
Phenomena, interesting. You mind sharing a sample HTML page? Is it a constant offset or depending on the specific HTML? – Ortwin Gentz Dec 05 '12 at 08:35
-
Maybe he get the smaller size because of webView.scalesPageToFit = YES; ... Im having an issue, my webView doesn't change their size, but I log the old and new size and apparently the new size its setted but it doesn't change it on the view... – norman784 Jan 22 '13 at 14:48
-
@testing if you just want to know the size but not change it just skip the `aWebView.frame = frame;` line. – stigi Aug 23 '13 at 13:33
-
It is the right method to determine height of UIWebView. I tested and getting desired result.(iOS 8.0, iPhone 6) – rakeshNS Sep 23 '14 at 10:11
-
@OrtwinGentz I tried This but when I scroll down the page become White and the Content is not shown, please check my post over here : http://stackoverflow.com/questions/28465222/implementing-uiwebview-inside-uiscrolview – Chlebta Feb 12 '15 at 10:30
-
@Chlebta I've commented on your post. As your own log messages show, the content height calculation of the webView is correct. I suspect there's some other issue with your view hierarchy. – Ortwin Gentz Feb 12 '15 at 11:15
-
-
Better solution for me (UIWebView in UICollectionViewCell): CGRect frame = webView.frame; CGRect oldFrame = frame; frame.size.height = 1; webView.frame = frame; CGSize fittingSize = [webView sizeThatFits:CGSizeZero]; webView.frame = oldFrame; – evya Mar 16 '15 at 11:57
-
@evya of course your adaptation makes sense if you just want to determine the height and not set the webView frame to it. – Ortwin Gentz Mar 17 '15 at 10:07
-
HELLO, I used this code. The heigh is calculated wrong when I have too many images. If I reload page the heigh calculates right! How to fix that? – Yestay Muratov Jun 09 '15 at 13:05
-
Hello, this approach calculates the height in wrong way. But if reload the page ( I am using pageviewcontroller) the height is right. I dont know why it cant calculate on its first time... – Yestay Muratov Jun 09 '15 at 18:03
-
Probably your web page is using AJAX or dynamically changes the content after the initial load. In this case you have to wait for subsequent delegate calls. Alternatively you might want to test the JavaScript based approach I linked in my answer. – Ortwin Gentz Jun 09 '15 at 18:26
I have another solution that works great.
On one hand, Ortwin's approach & solution works only with iOS 6.0 and later, but fails to work correctly on iOS 5.0, 5.1 and 5.1.1, and on the other hand there is something that I don't like and can't understand with Ortwin's approach, it's the use of the method [webView sizeThatFits:CGSizeZero]
with the parameter CGSizeZero
: If you read Apple Official documentation about this methods and its parameter, it says clearly :
The default implementation of this method returns the size portion of the view’s bounds rectangle. Subclasses can override this method to return a custom value based on the desired layout of any subviews. For example, a UISwitch object returns a fixed size value that represents the standard size of a switch view, and a UIImageView object returns the size of the image it is currently displaying.
What I mean is that it's like he came across his solution without any logic, because reading the documentation, the parameter passed to [webView sizeThatFits: ...]
should at least have the desired width
. With his solution, the desired width is set to the webView
's frame before calling sizeThatFits
with a CGSizeZero
parameter. So I maintain this solution is working on iOS 6 by "chance".
I imagined a more rational approach, which has the advantage of working for iOS 5.0 and later... And also in complex situations where more than one webView (With its property webView.scrollView.scrollEnabled = NO
is embedded in a scrollView
.
Here is my code to force the Layout of the webView
to the desired width
and get the corresponding height
set back to the webView
itself:
Obj-C
- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
aWebView.scrollView.scrollEnabled = NO; // Property available in iOS 5.0 and later
CGRect frame = aWebView.frame;
frame.size.width = 200; // Your desired width here.
frame.size.height = 1; // Set the height to a small one.
aWebView.frame = frame; // Set webView's Frame, forcing the Layout of its embedded scrollView with current Frame's constraints (Width set above).
frame.size.height = aWebView.scrollView.contentSize.height; // Get the corresponding height from the webView's embedded scrollView.
aWebView.frame = frame; // Set the scrollView contentHeight back to the frame itself.
}
Swift 4.x
func webViewDidFinishLoad(_ aWebView: UIWebView) {
aWebView.scrollView.isScrollEnabled = false
var frame = aWebView.frame
frame.size.width = 200
frame.size.height = 1
aWebView.frame = frame
frame.size.height = aWebView.scrollView.contentSize.height
aWebView.frame = frame;
}
Note that in my example, the webView
was embedded in a custom scrollView
having other webViews
... All these webViews
had their webView.scrollView.scrollEnabled = NO
, and the last piece of code I had to add was the calculation of the height
of the contentSize
of my custom scrollView
embedding these webViews
, but it was as easy as summing my webView
's frame.size.height
computed with the trick described above...
-
3This is much more elegant than the accepted solution, and it doesn't rely undocumented and undefined behavior. It's much less hackish than inserting javascript. I wish I could upvote this 64 times. – bugloaf Nov 20 '12 at 19:36
-
That's exactly what I tryed to explain. Thank you. And it great advantage is that it seems to work under all iOS versions. – Phenomena Nov 29 '12 at 21:10
-
The solution looks nice indeed, but be careful if you're still targeting iOS 4.x. `-[UIWebView scrollView]` is available in iOS 5.0 or later only. – Ortwin Gentz Nov 29 '12 at 22:01
-
Yes I know ! It's only working from iOS 5.0 and above... But what I like about it is that there is no magic : Read the comments in the code and you will understand how it works. – Phenomena Dec 05 '12 at 00:23
-
2I tried this and a similar solution and it turned out that this only works, if the webview or the view it's embedded in, are already on screen. If you try this before adding the webview to the view hierarchy, the result will be the manual size height. – k1th Jun 11 '13 at 13:00
-
1the other solution doesn't work every times, don't know why, but this on does the trick !!! this should be tagged a the right answer. – Vassily Jul 15 '13 at 12:04
-
Haven't double checked, but seems to me that the height of the UIWebView need to be reset to 1 before you load the html, or if the final height smaller than the original, it won't shrink. – i-- Dec 18 '13 at 03:21
-
Top quality answer. I wasn't comfortable with CGSizeZero either. Thanks Phenomena! – Custom Bonbons Jan 14 '15 at 14:19
-
best part for me is frame.size.height = aWebView.scrollView.contentSize.height; . Thanks helped alot. – Rajal Jan 20 '15 at 11:20
-
@Phenomena I tried This but when I scroll down the page become White and the Content is not shown, please check my post over here : http://stackoverflow.com/questions/28465222/implementing-uiwebview-inside-uiscrolview – Chlebta Feb 12 '15 at 10:32
-
-
I am trying to implement your solution, but seems that it is causing the content below to overlap the UIWebView (this is in iOS8 and iOS9) – stradled Feb 10 '16 at 11:51
-
The best part about this answer is that it gives you a chance to animate the resize from 1 to whatever! – Chris Aug 04 '16 at 15:32
Resurrecting this question because I found Ortwin's answer to only work MOST of the time...
The webViewDidFinishLoad
method may be called more than once, and the first value returned by sizeThatFits
is only some portion of what the final size should be. Then for whatever reason the next call to sizeThatFits
when webViewDidFinishLoad
fires again will incorrectly return the same value it did before! This will happen randomly for the same content as if it's some kind of concurrency problem. Maybe this behaviour has changed over time, because I'm building for iOS 5 and have also found that sizeToFit
works in much the same way (although previously this didn't?)
I have settled on this simple solution:
- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
CGFloat height = [[aWebView stringByEvaluatingJavaScriptFromString:@"document.height"] floatValue];
CGFloat width = [[aWebView stringByEvaluatingJavaScriptFromString:@"document.width"] floatValue];
CGRect frame = aWebView.frame;
frame.size.height = height;
frame.size.width = width;
aWebView.frame = frame;
}
Swift (2.2):
func webViewDidFinishLoad(webView: UIWebView) {
if let heightString = webView.stringByEvaluatingJavaScriptFromString("document.height"),
widthString = webView.stringByEvaluatingJavaScriptFromString("document.width"),
height = Float(heightString),
width = Float(widthString) {
var rect = webView.frame
rect.size.height = CGFloat(height)
rect.size.width = CGFloat(width)
webView.frame = rect
}
}
Update: I have found as mentioned in the comments this doesn't seem to catch the case where the content has shrunk. Not sure if it's true for all content and OS version, give it a try.

- 2,037
- 2
- 23
- 32

- 1,098
- 11
- 22
-
Have you included images or other assets in your web page? That might cause the additional firing of the delegate. Apart from that your solution only works when you don't give `webView.scalesPageToFit = YES` as @Sijo mentioned in the comment above. – Ortwin Gentz Aug 02 '12 at 08:31
-
Yeah that's probably it - your solution works fine in my text-only cases. But sizeThatFits not giving the right value during the final delegate call is the problem... very strange. How might we know which call is going to be the last so we don't attempt to use sizeThatFits until then? – Kieran Harper Aug 03 '12 at 00:10
-
If in the first delegate call you get the right result from sizeThatFits, can't you just ignore any following calls? – Ortwin Gentz Aug 03 '12 at 08:39
-
Yep but it's the other way around :) First delegate call can result in the wrong sizeThatFits, then that value sticks. It's as though either sizeThatFits is somehow modifying the web view so that any further sizeThatFits calls give the same result, or it's the setting of the frame while it's still loading that's doing it. – Kieran Harper Aug 05 '12 at 23:34
-
Perhaps it's re-layouting the web page? (Images or tables without width+height tags?) – Ortwin Gentz Aug 06 '12 at 08:26
-
Hi i used ur approach its worked fine for me when i use single WebView.But am using multiple WebViews in same view inside scrollview in my case the page freezes at webViewDidFinishLoad: please let me how can I achieve this. thanks – Murali Jul 11 '13 at 14:23
-
Murali I'm not sure what you mean about it freezing, and it's been a while since I looked at this problem so I'd suggest making a new SO question for your specific scenario (and include your code). That way a few more people will be able to help as well. – Kieran Harper Jul 15 '13 at 23:10
-
@KieranHarper I tried This but when I scroll down the page become White and the Content is not shown, please check my post over here : http://stackoverflow.com/questions/28465222/implementing-uiwebview-inside-uiscrolview – Chlebta Feb 12 '15 at 10:31
-
1This solution does not work correctly as well. Once you set larger page, and then set smaller one, you will always get returned the larger value. Seems like it "lazily" extends the internal views. Any workarounds for this? – Legoless Mar 04 '15 at 14:59
-
-
Can confirm I've returned to this to find it only works when the content grows, but doesn't go back down if it shrinks. Not sure if it depends on the content, or if newer iOS has changed anything. – Kieran Harper Mar 26 '16 at 06:07
-
This worked for me. As for the 'shrinking content', if your original frame size height is small (say 1pt), then the javascript method will work. Be sure to have `webview.scalesPageToFit = NO;` Of course maybe its impractical to have a frame size height of 1pt, but I happen to be using a UIWebView to render and cache image content offscreen. So this solution is great! – horseshoe7 Apr 14 '16 at 08:37
In Xcode 8 and iOS 10 to determine the height of a web view. you can get height using
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
NSLog(@"Webview height is:: %f", height);
}
OR for Swift
func webViewDidFinishLoad(aWebView:UIWebView){
let height: Float = (aWebView.stringByEvaluatingJavaScriptFromString("document.body.scrollHeight")?.toFloat())!
print("Webview height is::\(height)")
}

- 15,269
- 2
- 94
- 81
-
1Try to find using webview content size.. myWebView.scrollView.contentSize.height – Hardik Thakkar Oct 10 '16 at 04:15
A simple solution would be to just use webView.scrollView.contentSize
but I don't know if this works with JavaScript. If there is no JavaScript used this works for sure:
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
CGSize contentSize = aWebView.scrollView.contentSize;
NSLog(@"webView contentSize: %@", NSStringFromCGSize(contentSize));
}

- 15,269
- 2
- 94
- 81

- 2,662
- 7
- 28
- 31
AFAIK you can use [webView sizeThatFits:CGSizeZero]
to figure out it's content size.

- 14,911
- 1
- 36
- 54
For iOS10, I was getting 0 (zero) value of document.height
so document.body.scrollHeight
is the solution to get height of document in Webview. The issue can be resolved also for width
.

- 1,940
- 19
- 25
I'm using a UIWebView
that isn't a subview (and thus isn't part of the window hierarchy) to determine the sizes of HTML content for UITableViewCells
. I found that the disconnected UIWebView
doesn't report its size properly with -[UIWebView sizeThatFits:]
. Additionally, as mentioned in https://stackoverflow.com/a/3937599/9636, you must set the UIWebView
's frame
height
to 1 in order to get the proper height at all.
If the UIWebView
's height is too big (i.e. you have it set to 1000, but the HTML content size is only 500):
UIWebView.scrollView.contentSize.height
-[UIWebView stringByEvaluatingJavaScriptFromString:@"document.height"]
-[UIWebView sizeThatFits:]
All return a height
of 1000.
To solve my problem in this case, I used https://stackoverflow.com/a/11770883/9636, which I dutifully voted up. However, I only use this solution when my UIWebView.frame.width
is the same as the -[UIWebView sizeThatFits:]
width
.

- 1
- 1

- 30,998
- 16
- 147
- 256
-
1I have tried all of the examples in this thread, and using "document.height" to retrieve the height of the document is the most reliable. Additional HTML could be added outside of a container (such as DIV) which makes getElementById(...) unreliable in all of the tests I have performed. document.height works a treat. – John Rogers Sep 11 '13 at 03:16
None of the suggestions here helped me with my situation, but I read something that did give me an answer. I have a ViewController with a fixed set of UI controls followed by a UIWebView. I wanted the entire page to scroll as though the UI controls were connected to the HTML content, so I disable scrolling on the UIWebView and must then set the content size of a parent scroll view correctly.
The important tip turned out to be that UIWebView does not report its size correctly until rendered to the screen. So when I load the content I set the content size to the available screen height. Then, in viewDidAppear I update the scrollview's content size to the correct value. This worked for me because I am calling loadHTMLString on local content. If you are using loadRequest you may need to update the contentSize in webViewDidFinishLoad also, depending on how quickly the html is retrieved.
There is no flickering, because only the invisible part of the scroll view is changed.

- 2,729
- 27
- 25
-
I fear it's pure luck that the web view loads quick enough that it's finished at viewDidAppear. Probably this only works if the view appears animated so the the animation is long enough to load the content. I'd rather rely on `webViewDidFinishLoad` as the safe approach. – Ortwin Gentz Jun 01 '14 at 20:30
If your HTML contains heavy HTML-contents like iframe's (i.e. facebook-, twitter, instagram-embeds) the real solution is much more difficult, first wrap your HTML:
[htmlContent appendFormat:@"<html>", [[LocalizationStore instance] currentTextDir], [[LocalizationStore instance] currentLang]];
[htmlContent appendFormat:@"<head>"];
[htmlContent appendString:@"<script type=\"text/javascript\">"];
[htmlContent appendFormat:@" var lastHeight = 0;"];
[htmlContent appendFormat:@" function updateHeight() { var h = document.getElementById('content').offsetHeight; if (lastHeight != h) { lastHeight = h; window.location.href = \"x-update-webview-height://\" + h } }"];
[htmlContent appendFormat:@" window.onload = function() {"];
[htmlContent appendFormat:@" setTimeout(updateHeight, 1000);"];
[htmlContent appendFormat:@" setTimeout(updateHeight, 3000);"];
[htmlContent appendFormat:@" if (window.intervalId) { clearInterval(window.intervalId); }"];
[htmlContent appendFormat:@" window.intervalId = setInterval(updateHeight, 5000);"];
[htmlContent appendFormat:@" setTimeout(function(){ clearInterval(window.intervalId); window.intervalId = null; }, 30000);"];
[htmlContent appendFormat:@" };"];
[htmlContent appendFormat:@"</script>"];
[htmlContent appendFormat:@"..."]; // Rest of your HTML <head>-section
[htmlContent appendFormat:@"</head>"];
[htmlContent appendFormat:@"<body>"];
[htmlContent appendFormat:@"<div id=\"content\">"]; // !important https://stackoverflow.com/a/8031442/1046909
[htmlContent appendFormat:@"..."]; // Your HTML-content
[htmlContent appendFormat:@"</div>"]; // </div id="content">
[htmlContent appendFormat:@"</body>"];
[htmlContent appendFormat:@"</html>"];
Then add handling x-update-webview-height-scheme into your shouldStartLoadWithRequest:
if (navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeOther) {
// Handling Custom URL Scheme
if([[[request URL] scheme] isEqualToString:@"x-update-webview-height"]) {
NSInteger currentWebViewHeight = [[[request URL] host] intValue];
if (_lastWebViewHeight != currentWebViewHeight) {
_lastWebViewHeight = currentWebViewHeight; // class property
_realWebViewHeight = currentWebViewHeight; // class property
[self layoutSubviews];
}
return NO;
}
...
And finally add the following code inside your layoutSubviews:
...
NSInteger webViewHeight = 0;
if (_realWebViewHeight > 0) {
webViewHeight = _realWebViewHeight;
_realWebViewHeight = 0;
} else {
webViewHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"content\").offsetHeight;"] integerValue];
}
upateWebViewHeightTheWayYorLike(webViewHeight);// Now your have real WebViewHeight so you can update your webview height you like.
...
P.S. You can implement time delaying (SetTimeout and setInterval) inside your ObjectiveC/Swift-code - it's up to you.
P.S.S. Important info about UIWebView and Facebook Embeds: Embedded Facebook post does not shows properly in UIWebView

- 1
- 1

- 1,827
- 1
- 22
- 19
-
This is interesting! Could you describe what the script part does and how it can be tweaked if needed? It looks like it will periodically check the height, but there's multiple time intervals involved? – Kieran Harper Mar 26 '16 at 06:05
-
When using webview as a subview somewhere in scrollview, you can set height constraint to some constant value and later make outlet from it and use it like:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
webView.scrollView.scrollEnabled = NO;
_webViewHeight.constant = webView.scrollView.contentSize.height;
}

- 31
- 2
This's weird!
I tested the solutions both sizeThatFits:
and [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"]
are NOT working for me.
However, I found an interesting easy way to get the right height of webpage content. Currently, I used it in my delegate method scrollViewDidScroll:
.
CGFloat contentHeight = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
Verified in iOS 9.3 Simulator/Device, good luck!
EDIT:
Background: The html content is calculated by my string variable and HTTP content template, loaded by method loadHTMLString:baseURL:
, no registered JS scripts there.

- 5,777
- 2
- 37
- 69
I'm also stuck on this problem, then I realized that if I want to calculate the dynamic height of the webView, I need to tell the width of the webView first, so I add one line before js and it turns out I can get very accurate actual height.
The code is simple like this:
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//tell the width first
webView.width = [UIScreen mainScreen].bounds.size.width;
//use js to get height dynamically
CGFloat scrollSizeHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
webView.height = scrollSizeHeight;
webView.x = 0;
webView.y = 0;
//......
}
Xcode8 swift3.1:
- Set webView height to 0 first.
- In
webViewDidFinishLoad
Delegate:
let height = webView.scrollView.contentSize.height
Without step1, if webview.height > actual contentHeight, step 2 will return webview.height but not contentsize.height.

- 5,652
- 2
- 34
- 34
-
This is the reason why I could not get required frame in my case.. upvoted – NSPratik Feb 14 '19 at 13:41
Also in iOS 7 for proper working of all of mentioned methods add this in your view controller viewDidLoad
method:
if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
self.automaticallyAdjustsScrollViewInsets = NO;
}
Otherwise neither of methods would work as it should.

- 29,441
- 10
- 93
- 100

- 3,133
- 1
- 29
- 31