Insert CSS into loaded HTML in UIWebView / WKWebView

Insert CSS into loaded HTML in UIWebView / WKWebView

我能够成功获取 HTML 内容并显示到我的 UIWebView 中。

但想通过添加外部 CSS 文件来自定义内容。我只能更改文本和字体的大小。我尝试了所有可能的解决方案来进行更改,但它不起作用 - 它没有显示任何更改。

下面是我的代码

HTMLNode* body = [parser body];
HTMLNode* mainContentNode = [body  findChildWithAttribute:@"id" matchingName:@"main_content" allowPartial:NO];
NSString *pageContent = [NSString stringWithFormat:@"%@%@", cssString, contentHtml];
        [webView loadHTMLString:pageContent baseURL:[NSURL URLWithString:@"http://www.example.org"]];

-(void)webViewDidFinishLoad:(UIWebView *)webView1{
    int fontSize = 50;
    NSString *font = [[NSString alloc] initWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", fontSize];
    NSString *fontString = [[NSString alloc] initWithFormat:@"document.getElementById('body').style.fontFamily=\"helvetica\""];

    [webView1 stringByEvaluatingJavaScriptFromString:fontString];
    [webView1 stringByEvaluatingJavaScriptFromString:font];
}

请帮我获取我认为的 css 样式表。

你可以这样做:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSString *cssString = @"body { font-family: Helvetica; font-size: 50px }"; // 1
    NSString *javascriptString = @"var style = document.createElement('style'); style.innerHTML = '%@'; document.head.appendChild(style)"; // 2
    NSString *javascriptWithCSSString = [NSString stringWithFormat:javascriptString, cssString]; // 3
    [webView stringByEvaluatingJavaScriptFromString:javascriptWithCSSString]; // 4
}

此代码的作用:

// 1 : 定义一个包含所有 CSS 声明的字符串

// 2 : 定义一个 javascript 字符串,它创建一个新的 <style> HTML DOM 元素并向其中插入 CSS 声明。实际上插入是在下一步完成的,现在只有 %@ 占位符。我这样做是为了防止线路变得太长,但是步骤 2 和步骤 3 可以一起完成。

// 3 : 合并2个字符串

// 4 : 在 UIWebView

中执行 javascript

要使其正常工作,您的 HTML 必须有一个 <head></head> 元素。

编辑:

您还可以从本地 css 文件(在本例中名为 "styles.css")加载 css 字符串。只需将步骤 //1 替换为以下内容:

NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *cssString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

作为另一种选择,您可以将 <link> 元素注入 <head> 以加载 CSS 文件:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
    NSString *javascriptString = @"var link = document.createElement('link'); link.href = '%@'; link.rel = 'stylesheet'; document.head.appendChild(link)";
    NSString *javascriptWithPathString = [NSString stringWithFormat:javascriptString, path];
    [webView stringByEvaluatingJavaScriptFromString:javascriptWithPathString];
}

此解决方案最适合大型 CSS 文件。不幸的是,它不适用于远程 HTML 文件。仅当您想将 CSS 插入已下载到您的应用程序的 HTML 时才可以使用它。

更新:WKWebView / Swift 3.x

当您使用 WKWebView 时,由于 WKWebView 的安全设置,注入 <link> 元素不起作用。

您仍然可以将 css 作为字符串注入。在您的代码 //1 中创建 CSS 字符串或将其放入本地文件 //2。请注意,对于 WKWebView,您必须在 WKNavigationDelegatewebView(_:didFinish:) 方法中进行注入:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    insertCSSString(into: webView) // 1
    // OR
    insertContentsOfCSSFile(into: webView) // 2
}

func insertCSSString(into webView: WKWebView) {
    let cssString = "body { font-size: 50px; color: #f00 }"
    let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
    webView.evaluateJavaScript(jsString, completionHandler: nil)
}

func insertContentsOfCSSFile(into webView: WKWebView) {
    guard let path = Bundle.main.path(forResource: "styles", ofType: "css") else { return }
    let cssString = try! String(contentsOfFile: path).trimmingCharacters(in: .whitespacesAndNewlines)
    let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
    webView.evaluateJavaScript(jsString, completionHandler: nil)
}

有关更完整的详细信息,请参阅@joern 接受的答案。我添加这个答案是因为我 运行 遇到了一个奇怪的边缘情况。我的特定用例需要使用 class="dialog"div 添加样式。出于某种原因,使用 .dialogdiv 的样式无法正常工作,但其他类型的样式可以正常工作。最后我使用以下设置 dialog

的宽度
let width = Int(webView.bounds.width)
let script = "document.getElementsByClassName(\"dialog\")[0].style.width = \"\(width)px\""
webView.evaluateJavaScript(script)

由于 UIWebView 在 iOS 12 中被弃用,我将只回答 WKWebView。 我已经像接受的答案中描述的那样实现了 CSS 加载。问题是有时从没有 CSS 的 HTML 到 CSS 的 HTML 的过渡是可见的。
我认为更好的方法是使用 WKUserScript 像这样注入 CSS:

lazy var webView: WKWebView = {
    guard let path = Bundle.main.path(forResource: "style", ofType: "css") else {
        return WKWebView()
    }

    let cssString = try! String(contentsOfFile: path).components(separatedBy: .newlines).joined()
    let source = """
      var style = document.createElement('style');
      style.innerHTML = '\(cssString)';
      document.head.appendChild(style);
    """

    let userScript = WKUserScript(source: source,
                                  injectionTime: .atDocumentEnd,
                                  forMainFrameOnly: true)

    let userContentController = WKUserContentController()
    userContentController.addUserScript(userScript)

    let configuration = WKWebViewConfiguration()
    configuration.userContentController = userContentController

    let webView = WKWebView(frame: .zero,
                            configuration: configuration)
    return webView
}()

您可以在 blog post.

中阅读有关此方法的更多信息

与其将 css 与样式标签一起应用,不如将其与 link 标签一起应用:

func insertContentsOfCSSFile2(into webView: WKWebView) {
    guard let path = Bundle.main.path(forResource: "resource", ofType: "css") else { return }                
    let csFile = "var head = document.getElementsByTagName('head')[0];var link = document.createElement('link'); link.rel = 'stylesheet';link.type = 'text/css';link.href = '\(path)';link.media = 'all';head.appendChild(link);"

    webView.evaluateJavaScript(csFile) {(result, error) in
        if let error = error {
            print(error)
        }
    }
}

我已经测试过了。 它工作正常。

你需要在 apple 样式之前添加这个 header 到 HTML

let fontName = UIFont.systemFont(ofSize: 17.0).fontName
    let htmlContent = """
    <header>
    <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no'>
    </header>
    <style type='text/css'>
    img{max-height: 100%; min-height: 100%; height:auto; max-width: 100%; width:auto;margin-bottom:5px;}
    p{text-align:left|right|center; line-height: 180%; font-family: '\(fontName)'; font-size: 17px;}
    iframe{width:100%; height:250px;}
    </style> \(html)
    """
    webView.loadHTMLString(htmlContent, baseURL: Bundle.main.bundleURL)

我尝试了 Amer Hukic 的回答。但并没有像现在这样工作。我在 html 头标签之间添加了以下代码。

<link rel="stylesheet" href="style.css">