5

I’m experiencing a problem with a WKWebView on setting the magnification property.

I expecting the content to resize to fit like it does in Safari. But I can’t achieve this. When setting the magnification to a value less than 1.0 is the following.

enter image description here

The extra space is not used and a margin occurs. In Safari zooming out results in smaller text and image size but the extra space is actually used.

enter image description here

I'm using InterfaceBuild with XIB files wire up the view.

enter image description here

enter image description here

enter image description here

Also, I enable magnification in viewDidLoad.

webView.allowsMagnification = YES;

I also tried the following with no success:

webView.translatesAutoresizingMaskIntoConstraints = NO;
webView.autoresizesSubviews = NO;
webView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;

Any hint would be very much appreciated.

Jan Linxweiler
  • 382
  • 2
  • 9
  • you can use auto layout. It's much easier. Just add 4 margin layouts: top, left, bottom and right. should be straight forward – Ryan Ho May 10 '18 at 18:44
  • Thx Tai, I tried Auto Layout but it didn't change anything ... get the same result. Resizing the window works fine in both cases as long as I don't zoom in or out. – Jan Linxweiler May 10 '18 at 21:20
  • how do you zoom in and out? btw – Ryan Ho May 10 '18 at 21:32
  • To zoom I set the magnification property of the WKWebView. – Jan Linxweiler May 11 '18 at 08:31
  • 1
    Did you try to load another website? If it loads fine, it just might be the website it is. If the website has the viewport meta tag in the header tag like this, ``, it should work. I also tried loading apple.com with WKWebview, setting magnification to 0.3 and it looked good. – Ryan Ho May 11 '18 at 18:19
  • Hi Tai! Yes I tried different websites and also experimented with different viewport configurations. Is it possible for you to post your demo project? – Jan Linxweiler May 12 '18 at 08:57
  • if let url = URL(string: "https://www.apple.com/") { let urlRequest = URLRequest(url: url) webview.load(urlRequest) webview.navigationDelegate = self webview.magnification = 0.2 } – Ryan Ho May 14 '18 at 22:16
  • not sure how you implemented it – Ryan Ho May 14 '18 at 22:16

3 Answers3

4

The problem is that WKWebView's magnification property doesn't do what you think it does. What it does is that it scales the rendered page as a whole (think taking a bitmap or image and resizing it).

What you want is the dynamic scaling capability that Safari (and other browsers) have, generally referred to as "zooming". This is different from magnification, as it scales the layout of the page. This scales up or down the font sizes, element sizes, and so on, of a page individually.

There's no native (public) API to zoom a page like Safari does, but you can do pretty much the same thing by taking advantage of the CSS zoom property. Here's an extension that does just that:

extension WKWebView {

    func zoom(to zoomAmount: CGFloat) {
        evaluateJavaScript("document.body.style.zoom = '\(zoomAmount)'", completionHandler: nil)
    }

}

It can be used like this:

webView.zoom(to: 0.9)
mattsven
  • 22,305
  • 11
  • 68
  • 104
  • The problem with this is that it doesn't cause the layout to update, just makes things smaller. it's not the same as pressing Cmd-+/- in Safari or chrome – Jonathan. Mar 19 '19 at 10:19
  • I don't understand what you mean. This functions almost identically to `CMD` `+` or `CMD` `-`. (You will need to adjust the value in `zoom(to:)`, of course) – mattsven Mar 19 '19 at 11:22
  • Yes, I've done that but for responsive websites it doesn't relayout the content, just makes it smaller. eg a mobile sized layout doesn't become a desktop layout – Jonathan. Mar 19 '19 at 12:12
  • @Jonathan. Oh, that's different, but I understand what you were looking for now. Your solution is probably the best (and only) way to do this. – mattsven Mar 19 '19 at 23:23
3

To get as close to what Cmd +/- does in Safari/Chrome I increase the frame of the WKWebView and then transform the layer in the inverse:

    var zoomLevel: CGFloat = 1

    private func didTapZoomOut() {
        zoomLevel -= 0.2
        needsLayout = true
    }

    override func layout() {
        super.layout()
        webView.frame.size = CGSize(width: frame.width * (1/zoomLevel), height: frame.height * (1/zoomLevel))
        webView.layer?.transform = CATransform3DMakeScale(zoomLevel, zoomLevel, 1)
    }

This also causes the scrollbar to shrink but for my use case this isn't important.

Jonathan.
  • 53,997
  • 54
  • 186
  • 290
2

@mattsven answer seems to be the right one.Here's the objective c variant of his solution:

NSString *jsCommand = [NSString stringWithFormat:@"document.body.style.zoom = 1.5;"];
[[wkWebView evaluateJavaScript:jsCommand completionHandler:^(NSString *result, NSError *error) {
if(error != nil) {
    NSLog(@"Error: %@",error);
    return;
}

NSLog(@" Success");
}];

It seems that WKWebView doesn't has a scalePagesToFit as UIWebView of iOS.

References.one two

Tibin Thomas
  • 1,365
  • 2
  • 16
  • 25