如何在我自己的服务器上托管Google Web字体?


271

我需要在内联网应用程序上使用一些Google字体。客户端可能有也可能没有互联网连接。阅读许可条款,似乎其法律许可。


6
我了解的是,它不像下载一个文件并保存那样简单。每种浏览器都支持不同的字体格式,而google并没有提供直接简便的方法来获取所有必需的文件,以使字体在所有浏览器中都能正常工作。
Samarth Bhargava 2012年

1
您可以从链接的样式表中获取所有URI。
fuxia 2012年

38
是的,我可以自己弄清所有细节,也可以问一个问题,看看是否有人以前做过并且可以分享经验和脚本
Samarth Bhargava 2012年

2
嗯,Google fonts.googleapis.com/css?根据您的UA标头(阅读器:浏览器)返回不同的答案➝因此,它们仅提供当前浏览器的需求。如果要获取所有需要的字体(甚至只是URL),则将需要从不同的浏览器分别加载多个css文件。具有不同的伪造标题,以获取所有所需的信息。
Frank Nocke

Answers:


217

请记住,我的答案已经老了很多。

下面还有其他技术上更复杂的答案,例如:

因此,不要让这是当前接受的答案这一事实给您以为这仍然是最好的答案。


您现在还可以通过github上的google / font存储库下载google的整个字体集。他们还提供了〜420MB字体的zip快照


首先,您要以压缩包的形式下载字体选择,为您提供一堆真字体。将它们复制到公共位置,以及可以从CSS链接到的位置。

在google webfont下载页面上,您会找到一个包含链接,如下所示:

http://fonts.googleapis.com/css?family=Cantarell:400,700,400italic,700italic|Candal

它通过一系列@font-face定义链接到定义字体的CSS 。

在浏览器中将其打开,以将其复制并粘贴到您自己的CSS中,然后修改网址以包含正确的字体文件和格式类型。

所以这:

@font-face {
  font-family: 'Cantarell';
  font-style: normal;
  font-weight: 700;
  src: local('Cantarell Bold'), local('Cantarell-Bold'), url(http://themes.googleusercontent.com/static/fonts/cantarell/v3/Yir4ZDsCn4g1kWopdg-ehHhCUOGz7vYGh680lGh-uXM.woff) format('woff');
}

变成这个:

/* Your local CSS File */
@font-face {
    font-family: 'Cantarell';
    font-style: normal;
    font-weight: 700;
    src: local('Cantarell Bold'), local('Cantarell-Bold'), url(../font/Cantarell-Bold.ttf) format('truetype');
}

如您所见,以这种方式在您自己的系统上托管字体的缺点是,您将自己限制为真正的字体格式,而google webfont服务则由访问设备确定将传输哪些格式。

此外,我必须.htaccess在目录中添加一个文件,其中包含包含mime类型的字体,以避免在Chrome Dev Tools中弹出错误。

对于此解决方案,仅需要真正的类型,但是当您还希望包含不同的字体(例如)时,定义更多的类型不会带来任何损害font-awesome

#.htaccess
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf
AddType application/x-font-woff .woff

37
您不限于TrueType,也只需要下载.woff文件即可。将“ http://themes.googleusercontent.com/static/fonts/cantarell/v3/...80lGh-uXM.woff”放入网络浏览器,将其另存为“ /fonts/Cantarell-Bold.woff”并更新匹配的CSS(url('/ fonts / Canterell-Bold.woff'))
安东尼·布里格斯

2
Google提供多种字体格式是有原因的-TrueType在旧的浏览器上不起作用。WOFF是W3C标准。
Michael McGinnis 2014年

3
向下滚动到bash脚本解决方案-太棒了!
MaxVölkel博士2015年

3
该文件根据所使用的浏览器更改内容。
克里,

3
与下面列出的替代方案相比,此响应的部署更加复杂。从技术角度来说,它在几个方面也是不正确的(对TTF没有限制,TTF是一个坏主意,这会在每个浏览器中产生不同的结果,因为有相同的来源,所以您不能在任何公共的地方托管字体)。请不要这样做,请使用以下其他答案之一。
罗宾·贝荣

202

有一个工具localfont.com可帮助您下载所有字体变体。它还会生成相应的CSS进行实施。 不推荐使用

localfont已关闭。相反,如Damir所建议,您可以使用google-webfonts-helper



尽管很棒,但是当您碰巧需要其他语言版本的字体时,您必须找到另一种解决方案
anges244 2013年

那么不同的字符集呢?
体外

1
Google开发人员在这里说,自托管Google字体有其自身的缺点,请查看这些技巧以使用Google字体CDN并提高页面速度。
shaijut

@PauloCoghi该工具可能会报告该网站可访问,但由于我和许多其他人无法查看,显然存在问题。
Lawyerson


63

我编写了一个bash脚本,该脚本使用不同的用户代理在Google的服务器上获取CSS文件,然后将不同的字体格式下载到本地目录,然后编写一个包含这些字体的CSS文件。请注意,该脚本需要Bash版本4.x。

有关脚本,请参见https://neverpanic.de/blog/2014/03/19/downloading-google-web-fonts-for-local-hosting/(我不在此处复制它,因此我只需要在其中更新一个地方,当我需要)。

编辑:移至https://github.com/neverpanic/google-font-download


4
这真棒!(我希望它能很好地运行,但尚未测试)。我多年来一直在搜寻类似这样的表格。别开玩笑了,我什至开始写自己的脚本,但还远远没有完成。它的震撼使很少有人会想要这个。Google将该字体隐藏在生成的字符串后面,并且仅在ttf中没有开放源代码库中的实际webfont文件。他们希望我们使用字体,希望我们使用服务器,因为他们滥用此字体来跟踪人员。即使是最了解隐私的人也可以从Google服务器嵌入字体。
redanimalwar 2015年

1
我唯一关心的是实际的字体许可,没有真正仔细研究它们。我所知道的是,字体许可证不同于GPL或MIT。那么,实际上我们是否合法地允许从Google服务器中捕获此字体并自行提供它们?再说一遍,我不敢相信Google只是为了让世界变得更好而放弃了所有这些字体,他们实际上是付钱给开发人员为他们制作开放字体,这样他们肯定会获得很多数据。并且,如果您不愿意这样做,则可以在没有Internet的情况下在本地测试此字体。
redanimalwar 2015年

2
这个答案应该更多,因为与localfont.com相比,此脚本可以下载所有字体格式和子集。
piotrekkr

我知道您会将我当作一个懒惰的人,但是作为Windows的普通用户,必须编译它等等才能使用它……
Lucas Bustamante

@LucasB不涉及编译。这是一个bash脚本。我知道Windows并不是Bash附带的,但是请随时以支持Windows的方式重新实现它。这只是我用例的一部分,所以我没有花任何时间在它上面。
neverpanic

14

CSS文件的内容(来自包含URL)取决于我从哪个浏览器查看它。例如,使用Chrome 浏览到http://fonts.googleapis.com/css?family=Open+Sans时,该文件仅包含WOFF链接。使用Internet Explorer(如下),它同时包含EOT和WOFF。我将所有链接粘贴到浏览器中以下载它们。

@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3fY6323mHUZFJMgTvxaG2iE.eot);
  src: local('Open Sans'), local('OpenSans'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3fY6323mHUZFJMgTvxaG2iE.eot) format('embedded-opentype'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
}

当您托管自己的Web字体时,您需要正确链接到每种字体类型,处理旧的浏览器错误等。当您使用Google Web Fonts(由Google托管)时,Google会自动链接到该浏览器的正确字体类型。


1
+1链接到该文章,该文章解释了要使用的“通用” CSS代码,而为现代浏览器提供了“精简”代码!
ItalyPaleAle 2014年

2
因此,我将需要以不同的格式巧妙地为浏览器提供服务。我知道我们不鼓励这样做,但是我们正在为某些中国客户提供网页,这是我们希望托管该网页的主要原因。他们屏蔽了大多数Google资源。
Lionel Chan


3

我有一个用PHP编写的脚本,类似于@neverpanic的脚本,可以自动从Google 下载CSS和字体(提示和不提示)。然后,它将根据用户代理从您自己的服务器中提供正确的CSS和字体。它保留了自己的缓存,因此用户代理的字体和CSS将仅下载一次。

处于成熟阶段,但可以在这里找到:DaAwesomeP / php-offline-fonts


2

当您想在自己的服务器上托管所有字体(或其中的某些字体)时,您可以从此存储库中下载字体并以所需的方式使用它:https : //github.com/praisedpk/Local-Google-Fonts

如果您只想解决Google字体随附的杠杆浏览器缓存问题,则可以使用其他字体CDN,并将字体包括为:

<link href="https://pagecdn.io/lib/easyfonts/fonts.css" rel="stylesheet" />

或特定的字体,如:

<link href="https://pagecdn.io/lib/easyfonts/lato.css" rel="stylesheet" />

1

我在grunt任务中使用了grunt-local-googlefont

module.exports = function(grunt) {

    grunt.initConfig({
       pkg: grunt.file.readJSON('package.json'),

        "local-googlefont" : {
            "opensans" : {
                "options" : {
                    "family" : "Open Sans",
                    "sizes" : [
                        300,
                        400,
                        600
                    ],
                    "userAgents" : [
                        "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)",  //download eot
                        "Mozilla/5.0 (Linux; U; Android 4.1.2; nl-nl; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", //download ttf
                        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1944.0 Safari/537.36" //download woff and woff2
                    ],
                    "cssDestination" : "build/fonts/css",
                    "fontDestination" : "build/fonts",
                    "styleSheetExtension" : "css",
                    "fontDestinationCssPrefix" : "fonts"

                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-local-googlefont');
 };

然后,要检索它们:

grunt local-googlefont:opensans

请注意,我使用的是原始的fork,在检索名称中带有空格的字体时,效果更好。


1

实际上,您可以直接从Google下载所有字体格式的变体,并将它们包含在CSS中,以从服务器提供服务。这样,您不必担心Google会跟踪您网站的用户。但是,缺点可能会降低您自己的投放速度。字体对资源的要求很高。我尚未对此问题进行任何测试,想知道是否有人有类似想法。




1

如果您使用的是Webpack,则可能对此项目感兴趣:https : //github.com/KyleAMathews/typefaces

例如,说您要使用Roboto字体:

npm install typeface-roboto --save

然后将其导入应用程序的入口点(主js文件):

import 'typeface-roboto'

1

您可以遵循使用PHP开发的脚本。您可以在其中使用脚本下载任何Google字体。它将下载字体并创建CSS文件,然后将其存档以zip格式存储。
您可以从GitHub https://github.com/sourav101/google-fonts-downloader下载源代码

$obj = new GoogleFontsDownloader;

if(isset($_GET['url']) && !empty($_GET['url']))
{
    $obj->generate($_GET['url']);
}

if(isset($_GET['download']) && !empty($_GET['download']) && $_GET['download']=='true')
{
    $obj->download();
}

/**
* GoogleFontsDownloader
* Easy way to download any google fonts.
* @author     Shohrab Hossain
* @version    1.0.0 
*/
class GoogleFontsDownloader
{
    private $url      = '';
    private $dir      = 'dist/';
    private $fontsDir = 'fonts/';
    private $cssDir   = 'css/';
    private $fileName = 'fonts.css';
    private $content  = '';
    private $errors   = '';
    private $success  = '';
    public  $is_downloadable  = false;

    public function __construct()
    {
        ini_set('allow_url_fopen', 'on');
        ini_set('allow_url_include', 'on');
    }

    public function generate($url = null)
    {
        if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) 
        {
            $this->errors .= "<li><strong>Invalid url!</strong> $url</li>";
        }
        else
        {
            $this->url = $url;
            // delete previous files
            $this->_destroy();
            // write font.css
            $this->_css();
            // write fonts
            $this->_fonts();
            // archive files
            $this->_archive();
        }  
        // show all messages
        $this->_message();
    }

    public function download()
    { 
        // Download the created zip file
        $zipFileName = trim($this->dir, '/').'.zip';
        if (file_exists($zipFileName))
        {
            header("Content-type: application/zip");
            header("Content-Disposition: attachment; filename = $zipFileName");
            header("Pragma: no-cache");
            header("Expires: 0");
            readfile("$zipFileName");

            // delete file 
            unlink($zipFileName);
            array_map('unlink', glob("$this->dir/*.*"));
            rmdir($this->dir);

        } 
    }   

    private function _archive()
    {
        if (is_dir($this->dir))
        {
            $zipFileName = trim($this->dir, '/').'.zip';
            $zip = new \ZipArchive(); 
            if ($zip->open($zipFileName, ZipArchive::CREATE) === TRUE) 
            {
                $zip->addGlob($this->dir. "*.*");
                $zip->addGlob($this->dir. "*/*.*");
                if ($zip->status == ZIPARCHIVE::ER_OK)
                {
                    $this->success .= '<li>Zip create successful!</li>';
                    $this->is_downloadable = true;
                }
                else 
                {
                    $this->errors .= '<li>Failed to create to zip</li>';
                } 
            } 
            else 
            {
                $this->errors .= '<li>ZipArchive not found!</li>';
            }  
            $zip->close(); 
        }
        else
        {
            $this->errors .= "<li><strong>File</strong> not exists!</li>";
        } 
    }   

    private function _css()
    {  
        $filePath = $this->dir.$this->cssDir.$this->fileName;
        $content  = $this->_request($this->url);
        if (!empty($content))
        {
            if (file_put_contents($filePath, $content))
            {
                $this->success .= "<li>$this->fileName generated successful!</li>";
                $this->content = $content; 
            }
            else
            {
                $this->errors .= '<li>Permission errro in $this->fileName! Unable to write $filePath.</li>';
            }
        }
        else
        {
            $this->errors .= '<li>Unable to create fonts.css file!</li>';
        }
    }

    private function _fonts()
    {
        if (!empty($this->content))
        {
            preg_match_all('#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $this->content, $match);
            $gFontPaths = $match[0];
            if (!empty($gFontPaths) && is_array($gFontPaths) && sizeof($gFontPaths)>0)
            {
                $count = 0;
                foreach ($gFontPaths as $url) 
                {
                    $name     = basename($url);
                    $filePath = $this->dir.$this->fontsDir.$name;
                    $this->content = str_replace($url, '../'.$this->fontsDir.$name, $this->content);

                    $fontContent  = $this->_request($url);
                    if (!empty($fontContent))
                    {
                        file_put_contents($filePath, $fontContent);
                        $count++;
                        $this->success .= "<li>The font $name downloaded!</li>";
                    }
                    else
                    {
                        $this->errors .= "<li>Unable to download the font $name!</li>";
                    } 
                }

                file_put_contents($this->dir.$this->cssDir.$this->fileName, $this->content);
                $this->success .= "<li>Total $count font(s) downloaded!</li>";
            }
        }
    }

    private function _request($url)
    {
        $ch = curl_init(); 
        curl_setopt_array($ch, array(
            CURLOPT_SSL_VERIFYPEER => FALSE,
            CURLOPT_HEADER         => FALSE,
            CURLOPT_FOLLOWLOCATION => TRUE,
            CURLOPT_URL            => $url,
            CURLOPT_REFERER        => $url,
            CURLOPT_RETURNTRANSFER => TRUE,
        ));
        $result = curl_exec($ch);
        curl_close($ch);

        if (!empty($result))
        {
            return $result;
        } 
        return false;
    }

    private function _destroy()
    {
        $cssPath = $this->dir.$this->cssDir.$this->fileName;
        if (file_exists($cssPath) && is_file($cssPath))
        {
            unlink($cssPath);
        } 
        else
        {
            mkdir($this->dir.$this->cssDir, 0777, true);
        }

        $fontsPath = $this->dir.$this->fontsDir;
        if (!is_dir($fontsPath))
        {
            mkdir($fontsPath, 0777, true);
        }
        else
        {
            array_map(function($font) use($fontsPath) {
                if (file_exists($fontsPath.$font) && is_file($fontsPath.$font))
                {
                    unlink($fontsPath.$font);
                }
            }, glob($fontsPath.'*.*')); 
        }
    }

    private function _message()
    {
        if (strlen($this->errors)>0)
        {
            echo "<div class='alert alert-danger'><ul>$this->errors</ul></div>";
        }  
        if (strlen($this->success)>0)
        {
            echo "<div class='alert alert-success'><ul>$this->success</ul></div>";
        } 
    } 
}

0

除了k0pernicus之外,我还建议使用本地服务最佳。这也是bash(v4)脚本,使网络服务器操作员能够从自己的网络服务器下载和提供Google网络字体。但是除了其他bash脚本之外,它还使用户能够完全自动化(通过cron等)提供最新的字体文件和css文件。


0

有一个非常简单的脚本,用纯Java编写,可以从Google Web字体链接下载所有字体(支持多种字体)。它还下载CSS文件并将其调整为本地文件。可以修改用户代理以获取除WOFF2以外的其他文件。看到 https://github.com/ssc-hrep3/google-font-download

生成的文件可以轻松地添加到构建过程中(例如,像这样的webpack构建vue-webpack)。


0

您可以从https://github.com/google/fonts下载源字体

之后,使用font-ranger工具将大型Unicode字体拆分为多个子集(例如拉丁文,西里尔字母)。您应该使用该工具执行以下操作:

  • 为您支持的每种语言生成子集
  • 使用unicode-range子设置来节省带宽
  • 从字体中消除膨胀并针对网络进行优化
  • 将字体转换为压缩的woff2格式
  • 为旧版浏览器提供.woff后备
  • 自定义字体加载和渲染
  • 使用@ font-face规则生成CSS文件
  • 自托管网络字体或在本地使用

Font-Rangerhttps : //www.npmjs.com/package/font-ranger

PS您也可以使用Node.js API自动执行此操作

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.