如何在我自己的服务器上托管谷歌web字体?

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

208592 次浏览

这在法律上是允许的,只要你遵守字体许可的条款——通常是OFL。

你需要一组网页字体格式,而字体松鼠Webfont生成器可以生成这些格式。

但是OFL要求在修改字体时重命名它们,使用生成器意味着修改它们。

请记住,我的回答已经过时了很多。

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

  • < a href = " https://stackoverflow.com/a/23174059/457268 " > neverpanic / google-font-download < / >
  • < a href = " https://stackoverflow.com/a/31801634/457268 " > google-webfont-helper < / >
  • < a href = " https://stackoverflow.com/a/28472199/457268 " > localfont < / >

所以,不要因为这是目前公认的答案,就以为这是最好的答案。


你现在也可以下载谷歌的整个字体集通过github在他们的谷歌/字体存储库。它们还提供了~420MB压缩快照他们的字体


首先下载压缩包的字体选择,为您提供一堆真正的字体类型。把它们复制到公共的地方,你可以从css中链接到的地方。

在谷歌webfont下载页面,你会发现一个包含链接如下:

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

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

在浏览器中打开它,将它们复制并粘贴到您自己的CSS中,并修改url以包括正确的字体文件和格式类型。

所以这个:

    @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');
}

正如您所看到的,以这种方式在您自己的系统上托管字体的一个缺点是,您将自己限制为真正的类型格式,而谷歌webfont服务则由访问设备决定将传输哪种格式。

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

对于这个解决方案,只需要true type,但是当你想包含不同的字体(比如font-awesome)时,定义more也没有坏处。

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

CSS文件的内容(来自include 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 Fonts(由谷歌托管)时,谷歌自动链接到该浏览器的正确字体类型。

我写了一个bash脚本,它在谷歌的服务器上使用不同的用户代理获取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

我有一个类似于@neverpanic的PHP脚本,自动从谷歌下载CSS和字体(有暗示的也有未暗示的)。然后,它根据用户代理从您自己的服务器提供正确的CSS和字体。它有自己的缓存,所以用户代理的字体和CSS只会被下载一次。

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

我在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

注意,我使用的是原始版本的一个分支,它在检索名称中有空格的字体时工作得更好。

实际上,您可以直接从谷歌下载所有字体格式变体,并将它们包含在您的css中,以从您的服务器提供服务。这样你就不必担心谷歌跟踪你网站的用户。然而,缺点可能会减慢你自己的发球速度。字体对资源的要求很高。我还没有在这个问题上做任何测试,不知道是否有人有类似的想法。

当你想要在你自己的服务器上托管所有字体(或其中一些)时,你可以从这个repo下载字体并以你想要的方式使用它:https://github.com/praisedpk/Local-Google-Fonts

如果你只是想这样做来修复谷歌Fonts附带的浏览器缓存问题,你可以使用替代字体CDN,并将字体包括为:

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

或一种特定的字体,如:

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

编辑:正如luckyrumo指出的那样,字体被放弃了,以支持:https://github.com/fontsource/fontsource

如果你正在使用Webpack,你可能会对这个项目感兴趣:https://github.com/KyleAMathews/typefaces

例如,你想使用Roboto字体:

npm install typeface-roboto --save

然后把它导入你的应用的入口点(主js文件):

import 'typeface-roboto'

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

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

  • 为您支持的每种语言生成子集
  • 使用unicode范围子集节省带宽
  • 删除臃肿从你的字体和优化他们的网页
  • 将字体转换为压缩的woff2格式
  • 为旧浏览器提供.woff备份
  • 自定义字体加载和渲染
  • 使用@font-face规则生成CSS文件
  • 自托管web字体或在本地使用它们

Font-Ranger: https://www.npmjs.com/package/font-ranger

附注:你也可以使用Node.js API自动化这个过程

你可以遵循使用PHP开发的脚本。 在那里你可以下载任何谷歌字体使用脚本。 它将下载字体,并创建一个CSS文件和存档压缩。
你可以从GitHub https://github.com/souravmsh/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>";
}
}
}

最简单的方法-使用google-webfonts-helper

假设我们想要托管字体Red Rose:

  • 打开google-webfonts-helper并在左上角过滤所需的字体(输入红玫瑰并输入..)
  • 从字符集中选择(默认为拉丁;如果你想要扩展支持,选择其他像latin-ext)
  • 选择样式(deafult是常规的)
  • 来自Copy CSS选项卡
    • 如果您希望只支持现代浏览器,请选择Modern Browser (woff2, woff)
    • 如果您希望支持所有浏览器,请选择Best Support(我选择了woff2, woff,ttf,svg,eot)
  • 如果你的字体文件不在../fonts/路径中,你可以编辑它来代表你的实际路径(对我来说是../assets/fonts/)
  • 复制CSS并保留以供将来使用
  • 下载名为red-rose-v1-latin-ext_latin的zip文件;解压并将所有字体直接放入你的assets/fonts目录中(基于你之前给出的)
  • 在您想要嵌入的样式表中,粘贴复制的CSS。如果你选择这些选项,它将如下所示
/* red-rose-regular - latin-ext_latin */
@font-face {
font-family: 'Red Rose';
font-style: normal;
font-weight: 400;
src: url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */
src: local('Red Rose Regular'), local('RedRose-Regular'),
url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */
url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.svg#RedRose') format('svg'); /* Legacy iOS */
}
/* Red Rose will now be available for use in your stylesheet, provide this font */


:root {
font-family: 'Red Rose', cursive, sans-serif;
}
  • 这一切!