119

I am updating my iOS app to replace UIWebView with WKWebView. However I don't understand how to achieve the same behavior with WKWebView. With UIWebView I used scalesPageToFit to ensure the web pag was displayed with the same size as the screen size (so as to appear full screen without scrolling).

I found that solution on the web however it does not work :

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    NSString *javascript = @"var meta = document.createElement('meta');meta.setAttribute('name', 'viewport');meta.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');document.getElementsByTagName('head')[0].appendChild(meta);";
    [webView evaluateJavaScript:javascript completionHandler:nil];
}
Nagarjun
  • 6,557
  • 5
  • 33
  • 51
olinsha
  • 1,195
  • 2
  • 8
  • 5
  • try this: `NSString* js = @"var meta = document.createElement('meta'); " "meta.setAttribute( 'name', 'viewport' ); " "meta.setAttribute( 'content', 'width = device-width' ); " "document.getElementsByTagName('head')[0].appendChild(meta)"; [webView stringByEvaluatingJavaScriptFromString: js];` replace your code with above code. – z22 Oct 10 '14 at 08:54
  • I gave it a try but I have the same result (by the way, the stringByEvaluatingJavaScriptFromString method does not exist in WKWebView so I kept my evaluateJavaScript:completionHandler call – olinsha Oct 10 '14 at 15:19
  • 1
    did you get a solution? – anoop4real May 24 '17 at 05:44

12 Answers12

142

you can also try the WKUserScript.

here's my working config:

NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";

WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
[wkUController addUserScript:wkUScript];

WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
wkWebConfig.userContentController = wkUController;

wkWebV = [[WKWebView alloc] initWithFrame:self.view.frame configuration:wkWebConfig];

you can add additional configuration to your WKWebViewConfiguration.

eNeF
  • 3,241
  • 2
  • 18
  • 41
  • 2
    Works great for me - only minor tweak was changing WKUserScriptInjectionTimeAtDocumentEnd to WKUserScriptInjectionTimeAtDocumentStart – sckor Mar 31 '15 at 20:54
  • 1
    If I change `WKUserScriptInjectionTimeAtDocumentEnd` to `WKUserScriptInjectionTimeAtDocumentStart` then it doesn't work for me. It doesn't add this script. any reason? – Mahesh K May 03 '16 at 18:17
  • you should check for other scripts that might be overwriting your custom script. – eNeF May 04 '16 at 08:45
  • 2
    Nice answer, but I would also add this script to avoid webkit changing the font sizes by itself: `var style = document.createElement('style');style.innerHTML = 'body { -webkit-text-size-adjust: none; }';document.getElementsByTagName('head')[0].appendChild(style);` – José Manuel Sánchez May 12 '16 at 10:57
  • @MahmoudAdam what do you mean it does not work with iOS9? I'm actually still using that in swift config. And not, that config will only work for iOS8 and later, iOS7 and below doesn't have webkit framework. – eNeF Jun 14 '16 at 12:01
  • @nferocious76 when I set `device-height` & `device-width` it does not work with iOS9 but when I sent them to exact numbers it works, Also do you have any idea to support different orientations? – Mahmoud Adam Jun 14 '16 at 12:04
  • @MahmoudAdam you should consider the injection time and 'nitWithFrame:' of your wkwebview – eNeF Jun 14 '16 at 12:06
  • 1
    This worked out great. I was trying to align a special title with Auto Layout using WKWebView. The height of the element from offsetHeight kept coming back too big until I added this script. Thanks for the help. – JamWils Dec 17 '16 at 00:18
  • I've faced some issues on iPad iOS8. – Timur Bernikovich Feb 02 '17 at 10:20
  • Looks like we need to change `device-width` to `=device-height` when in landscape on iOS. – Timur Bernikovich Feb 02 '17 at 10:47
  • @TimurBernikowich no.. just add support for handling orientation changed. and those two values should interchange.. on that note what issues did you encountered? – eNeF Feb 03 '17 at 08:18
  • @nferocious76 can you provide sample? I've tried opening my VC with web view in landspace without any rotations and it still appears incorrect. (width is limited to "device-portrait-width") – Timur Bernikovich Feb 03 '17 at 08:21
  • @nferocious76 This solutions works perfectly when only text content is on my loadRequest URL. But when image and text both are on the URL at that time image looks proper but text size looks smaller. – Vivek Shah May 25 '17 at 06:22
  • @VivekShah you probably need to add a config for your font sizes. – eNeF May 25 '17 at 08:43
  • Perfect. Thank you @nferocious76. – arango_86 Jun 20 '17 at 17:12
  • Working nice. Thanks. – Maheta Dhaval K Oct 19 '21 at 14:17
49

Echo of nferocious76's answer, in swift code: Swift2.x version

let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
let userScript = WKUserScript(source: jscript, injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: true)
let wkUController = WKUserContentController()
wkUController.addUserScript(userScript)
let wkWebConfig = WKWebViewConfiguration()
wkWebConfig.userContentController = wkUController
let youWebView = WKWebView(frame: CGRectZero, configuration: wkWebConfig)

swift3 version

let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let wkUController = WKUserContentController()
wkUController.addUserScript(userScript)
let wkWebConfig = WKWebViewConfiguration()
wkWebConfig.userContentController = wkUController
let yourWebView = WKWebView(frame: self.view.bounds, configuration: wkWebConfig)
air_bob
  • 1,317
  • 14
  • 26
27

Similar to @nferocious76's but in Swift language

var scriptContent = "var meta = document.createElement('meta');"
scriptContent += "meta.name='viewport';"
scriptContent += "meta.content='width=device-width';"
scriptContent += "document.getElementsByTagName('head')[0].appendChild(meta);"

webView.evaluateJavaScript(scriptContent, completionHandler: nil)
Efe Ariaroo
  • 1,052
  • 10
  • 10
  • Thanks! this also solved my problem to make html font size become bigger, didn't refresh from small to big. I'm using this to "refresh" the content font size and inner layout. – Nadi Hassan Jul 25 '17 at 14:17
19

I figured out below soultion. For making the content to fit with the device size.

func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {     for making the content to fit with the device size
    let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
    webView.evaluateJavaScript(jscript)
}
Ankita
  • 469
  • 4
  • 15
14

C# version, for use in Xamarin Custom Renderer:

string jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";

WKUserScript wkUScript = new WKUserScript((NSString)jScript, WKUserScriptInjectionTime.AtDocumentEnd, true);
WKUserContentController wkUController = new WKUserContentController();
wkUController.AddUserScript(wkUScript);

WKWebViewConfiguration wkWebConfig = new WKWebViewConfiguration();
wkWebConfig.UserContentController = wkUController;
WKWebView webView=new WKWebView(Frame, wkWebConfig);
fire in the hole
  • 1,171
  • 15
  • 34
  • Work like charm! – Divyesh Jul 17 '20 at 18:18
  • How does the custom renderer looks like? Do you inheriting from `WkWebViewRenderer`? Because `Control` as well as `SetNativeControl()` are unknown ... – testing Jul 24 '20 at 10:58
  • Ok it seems that you need to inherit from `ViewRenderer` and use `OnElementChanged(ElementChangedEventArgs e)`. – testing Jul 24 '20 at 15:51
  • Thank you for this it certainly helped resolve my Xamarin.Forms issue where HTML was being cut off even though I was resizing the height based on the content in `DidFinishNavigation` – Nick Peppers Dec 15 '21 at 19:58
13

Adding the below to my HTML script helped me.

<meta name="viewport" content="width=device-width, shrink-to-fit=YES">

It does the same as scalePageToFit in UIWebView.

refer: How to set iOS WkWebview zoom scale

Hepsiba
  • 131
  • 1
  • 2
5

Swift 5 solution:

let javaScript = """
    var meta = document.createElement('meta');
                meta.setAttribute('name', 'viewport');
                meta.setAttribute('content', 'width=device-width');
                document.getElementsByTagName('head')[0].appendChild(meta);
    """

webView.evaluateJavaScript(javaScript)
2

This work for me, I added two attributes in meta: initial-scale=1.0, shrink-to-fit=yes, that help fit text with html have a big image in html.

let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width, initial-scale=1.0, shrink-to-fit=yes'); document.getElementsByTagName('head')[0].appendChild(meta);"
        
let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)

let wkUController = WKUserContentController()
        
wkUController.addUserScript(userScript)
        
let wkWebConfig = WKWebViewConfiguration()
        
wkWebConfig.userContentController = wkUController

self.webView = WKWebView(frame: self.view.bounds, configuration: wkWebConfig)
Pascal Syma
  • 729
  • 1
  • 6
  • 19
1

None of this answers were working for me. I was trying to open an Amazon URL for a particular artist. Turns out that Amazon has a mobile responsive URL and a desktop URL. On desktop Safari, I changed to iPhone as user-agent (Develop > User Agent > Safari - iOS 13.1.3 - iPhone) and got the appropriate URL for mobile.

GIJoeCodes
  • 1,680
  • 1
  • 25
  • 28
1

This works for me to fit the image size within width of device for Swift 5
Helpful with dynamic html from server

func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
   
    let fontAdjust = "var style = document.createElement('style');style.innerHTML = 'body { -webkit-text-size-adjust: none; }';document.getElementsByTagName('head')[0].appendChild(style);"

    let imgAdjust = "var style = document.createElement('style');style.innerHTML = 'img { display: inline;height: auto;max-width: 100%; }';document.getElementsByTagName('head')[0].appendChild(style);"
webKitView.evaluateJavaScript(imgAdjust)

    webKitView.evaluateJavaScript(fontAdjust)
    webKitView.evaluateJavaScript(imgAdjust)
}

Martin Brisiak
  • 3,872
  • 12
  • 37
  • 51
0

Modern Swift code to use in an extension

extension WKWebView {

func addInitialScaleMetaTag() {
    evaluateJavaScript(
    """
        var meta = document.createElement("meta");
        meta.name = "viewport";
        meta.content = "initial-scale=1.0";
        document.getElementsByTagName('head')[0].appendChild(meta);
    """) { result, error in
        // handle error
    }
}

}

ph1lb4
  • 1,982
  • 17
  • 24
-1

// 100% work for me

func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
    //print(#function)
    let scriptFontSizeAdjustment = "var style = document.createElement('style');style.innerHTML = 'body { -webkit-text-size-adjust: none; }';document.getElementsByTagName('head')[0].appendChild(style);"

    let scriptImgSizeAdjustment = "var style = document.createElement('style');style.innerHTML = 'img { display: inline;height: auto;max-width: 100%; }';document.getElementsByTagName('head')[0].appendChild(style);"

    webKitView.evaluateJavaScript(scriptFontSizeAdjustment)
    webKitView.evaluateJavaScript(scriptImgSizeAdjustment)

}