配置Nginx禁止外网访问网站里的某个文件的方法

server {
    ...
    location = /test/test.ini {
        deny all;
    }
    ...
}

其中

  • location = /test/test.ini:这个配置会匹配精确的 URL 路径 /test/test.ini。
  • deny all:这条指令禁止所有的访问,任何请求访问该文件都会收到 403 Forbidden 错误。

完成配置后,重新加载 Nginx 配置:

sudo nginx -s reload

通过HTTPS访问网站,谷歌浏览器报错“使用了不受支持的协议ERR_SSL_VERSION_OR_CIPHER_MISMATCH”的原因及解决方法

我的软件环境:

Ubuntu 24

Nginx

Cloudflare DNS

我使用Let’s Encrypt的Cerbot为admin.larabbs.zuotijia.me申请SSL/TLS证书后,使用浏览器访问https://admin.larabbs.zuotijia.me网站报错:

  • 谷歌浏览器报错“使用了不受支持的协议ERR_SSL_VERSION_OR_CIPHER_MISMATCH”的原因及解决方法。
  • 火狐浏览器报错“连接到 admin.larabbs.zuotijia.me 时发生错误。无法安全地与对等端通信:没有双方共用的加密算法。错误代码:SSL_ERROR_NO_CYPHER_OVERLAP”

但是同样使用Let’s Encrypt的Cerbot为www.zuotijia.me申请SSL/TLS证书,能正常通过浏览器访问https://www.zuotijia.me网站。说明不是Cerbot的问题。

错误原因

错误原因是,在Cloudflare上使用的是Cloudflare免费提供的SSL通用证书(Cloudflare Universal SSL),它只支持根域名(yourwebsite.com)以及二级泛域名(*.yourwebsite.com),不支持三级及以上的域名。

解决方法

方法一,不要使用三级及以上的域名。

方法二,在Cloudflare的仪表板->SSL/TLS->概述界面

配置加密模式为“灵活”或“关闭”:

但这种方法不够安全,因此不推荐这种方法。

方法三,不要使用Cloudflare管理域名,使用其他域名服务提供商来管理你的域名。

参考

https://devsdawn.com/2021/10/cloudflare-multi-level-subdomains-ssl-error

https://developers.cloudflare.com/ssl/edge-certificates/additional-options/total-tls/error-messages

https://developers.cloudflare.com/ssl/edge-certificates/additional-options/total-tls

https://developers.cloudflare.com/ssl/edge-certificates/additional-options/total-tls/enable

https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates

https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/uploading

https://www.obodizhu.com/resouce-experience/perfect-solution-to-err_ssl_version_or_cipher_mismatch-error.html

https://www.cnblogs.com/yzbg/articles/17323611.html

https://community.cloudflare.com/t/topic/399346

在body元素上设置id属性的值作为CSS命名空间

比如说有2个页面index.html和about.html,共用同一份style.css,那么怎么区分index.html和about.html的CSS属性不致于混淆呢?

其中一种好用的解决方法是,给index.html的body元素设置id=”index”属性,给about.html的body元素设置id=”about”属性。在style.css文件里,分别使用#index和#about作为包含选择器的开头,分别用来限定index.html和about.html的CSS属性。例如:

/* index.html的CSS */
#index div {
    /* …. */
}

/* about.html的CSS */
#about  div {
    /* …. */
}

CSS网格Grid布局交互式指南

本文翻译自《An Interactive Guide to CSS Grid》。

CSS Grid是CSS语言中最令人惊叹的部分之一。它为我们提供了大量的新工具,可以用来创建复杂又流畅的布局。

CSS Grid非常复杂。我花了很长时间才真正适应它!

在本教程中,我将分享在我使用CSS Grid的过程中,我经历的一些精彩的时刻。你将学习这种布局模式的基础知识,并了解如何用它做一些很酷的事情。

浏览器支持情况?

CSS Grid是构建CSS布局的最现代的工具,但它并不是“前沿”。自2017年以来,所有主流浏览器都支持它!

根据caniuse的数据,97.8%的用户支持CSS Grid。Flexbox仅超过它约0.5%!

心智模型

CSS由几种不同的布局算法组成,每种算法都是为不同类型的用户界面设计的。默认布局算法Flow layout是为数字文档设计的。表格布局是为表格数据而设计的。Flexbox布局用于沿单个轴分配子条目。

CSS Grid是最新、最伟大的布局算法。它非常强大:我们可以用它来构建复杂的布局,这些布局可以根据许多约束流畅地适应。

在我看来,CSS Grid最不寻常的部分是网格结构行和列完全在CSS中定义

(译者注:案例请看原文)

使用CSS Grid,单个DOM节点被细分为行和列。在本教程中,我们用虚线突出显示行/列,但实际上它们是不可见的。

这太奇怪了!在所有其他布局模式中,创建这样的隔间的唯一方法是添加更多的DOM节点。例如,在Table布局中,每一行都使用<tr>创建,该行中的每个单元格都使用<td>或<th>创建:

<table>
  <tbody>
    <!-- First row -->
    <tr>
      <!-- Cells in the first row -->
      <td></td>
      <td></td>
      <td></td>
    </tr>

    <!-- Second row -->
    <tr>
      <!-- Cells in the second row -->
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </tbody>
</table>

与表格布局不同,CSS Grid允许我们完全从CSS内部管理布局。我们可以随心所欲地分割容器,创建我们的网格子节点可以用作锚点的隔间。

网格容器使用流式布局(Grid flow)

我们使用display属性选择网格布局模式:

.wrapper {
  display: grid;
}

默认情况下,CSS Grid使用单列,并将根据子条目的数量根据需要创建一行或多行。这被称为隐式网格,因为我们还没有明确定义任何结构。

这就是它在默认情况下如何工作的:

(译者注:案例请看原文)

隐式网格是动态的;将根据子条目的数量添加或删除一行或多行。每个子条目都有自己的一行。

默认情况下,网格的容器元素的高度由其子条目的数量决定。它动态地增长和收缩。有趣的是,这甚至不是一个“CSS网格”的特性;网格的容器元素仍在使用文档流布局(Flow layout),Flow布局中的块状元素(display:block)默认会动态地垂直增长以包含其内容。只有里面的子元素使用网格布局(Grid layout)来排列。

但是,如果我们给网格的容器元素一个固定的高度呢?在这种情况下,里面的行将平均分配它的高度,即每一行都有相同的高度:

(译者注:案例请看原文)

网格构建(Grid Construction)

默认情况下,CSS Grid将创建单列布局。我们可以使用grid-template-columns属性指定列:

(译者注:案例请看原文)

为清晰起见,添加了虚线

在上面的案例以及在整个教程中,我使用虚线来显示列和行之间的划分。在CSS网格布局中,这些线是不可见的,也无法使其可见。在本文章,这些虚线只做演示用。

通过grid-template-columns: 25% 75%;属性,我告诉CSS网格布局算法将元素分为两列。

列可以使用任何有效的CSS长度值来定义,包括像素、rems、视口单位等。此外,我们还可以使用一个新的单位——fr单位:

(译者注:案例请看原文)

fr代表“分数”。在这个例子中,我们说第一列消耗1单位的空间,而第二列消耗3单位的空间。这意味着总共有4个单位的空间,这成为分母。第一列消耗了1/4的可用空间,而第二列消耗了3/4。

fr单位为CSS网格带来了类似于Flexbox样式的灵活性。百分比和长度值创建了硬约束,而fr列可以根据需要自由增长和收缩,以包含其内容。

尝试缩小此容器以查看fr单位和百分比单位之间的差异:

(译者注:案例请看原文)

在上述案例中,我们的第一列有一张可爱的幽灵图片,它的宽度被设置为55px。但是,如果列太小而无法容纳它呢?

  • 基于百分比单位的列是刚性的,因此我们的图像会溢出,溢出到列外。
  • 基于fr单位的列是灵活的,因此列不会缩小到其最小内容的尺寸以下,即使这意味着会打破比例。

更准确地说:fr单位分配额外的空间。首先,列宽将根据列的内容计算。如果容器还有剩余空间,将根据fr单位的值进行按比例分配。这与我在《Flexbox交互式指南》中讨论的flex-grow属性的功能非常相似。

总的来说,这种灵活性是一件好事。百分比单位太严格了。

我们可以在gap中看到一个完美的例子。gap是一个神奇的CSS属性,它在网格中的所有列和行之间添加了固定数量的空间。

看看当我们在百分比单位和fr单位之间切换时会发生什么:

(译者注:案例请看原文)

请注意,当使用基于百分比单位的列时,内容是如何溢出到网格容器之外的。这是因为百分比单位是使用网格容器的总面积来计算的。这两列占用了网格容器内容区域的100%,并且不允许收缩。当我们添加16px的间隙时,这两列别无选择,只能溢出网格容器。

相比之下,fr单位是根据网格容器的额外空间计算的。在这种情况下,由于设置了间隙gap:16px;,网格容器的额外的空间减少了16px。CSS网格算法在两个网格列之间按比例分配剩余空间。

gapgrid-gap

当CSS Grid首次引入时,grid-gap属性用于在列和行之间添加空间。然而,很快,社区意识到,在Flexbox中拥有这个功能也会很棒。因此,该属性被赋予了一个更通用的名称:gap。

如今,grid-gap已被标记为弃用,浏览器将其取别名为gap。这两个属性做完全相同的事情。它们都有几乎相同的浏览器支持,约96%

因此,我建议使用gap而不是grid-gap,无论你是使用Flexbox还是CSS grid。但也不强制转换现有的grid-gap声明。

隐式的行和显式的行

如果我们在两列网格中添加两个以上的子元素,会发生什么?

好吧,让我们试试:

(译者注:案例请看原文)

有趣!我们的网格获得了第二行。网格算法希望确保每个子元素都有自己的网格单元。它将根据需要生成新行以实现这一目标。这在我们有可变数量的子元素(例如照片网格)并且我们希望网格能自动扩展的情况下很方便。

不过,在其他情况下,我们希望显式定义一行或多行,以创建特定的布局。我们可以使用grid-template-rows属性来实现这一点:

(译者注:案例请看原文)

通过定义grid-template-rows和grid-template-columns,我们创建了一个显式的网格。这非常适合构建页面布局,比如在本教程的顶部的“圣杯”布局。

重复助手

假设我们正在构建一个日历:

对于这种场景,CSS Grid是一个很好的工具。我们可以将其构造为7列网格,每列占用1个单位的空间:

.calendar {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

这是可行的,但要写出每一个1fr有点烦人。想象一下,如果我们有50列!

幸运的是,有一个更好的方法来解决这个问题:

.calendar {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

repeat函数将为我们进行复制/粘贴。我们只需要说我们想要7列,每列宽1fr。

以下是这个日历的完整代码:

(译者注:案例请看原文)

分配子项

默认情况下,CSS网格布局算法会将每个子元素分配到第一个未被占用的网格单元,就像商人在浴室地板上铺设瓷砖一样。

不过,有一件很酷的事情:我们可以将我们的子元素分配给任何一个单元格!甚至可以跨越多行/多列。

这是一个交互式演示,展示了CSS网格布局算法是如何工作的。单击/按下或拖动以将子元素放置在网格中:

(译者注:案例请看原文)

grid-row和grid-column 属性允许我们指定网格布局的子元素应占用的网格空间。

如果我们想让子对象占据一行或一列,我们可以通过一个编号来指定它。grid-column:3将设置子元素坐在第三列。

网格子元素还可以拉伸并跨越多行或多列。此语法使用斜线来描述开始和结束:

.child {
  grid-column: 1 / 4;
}

乍一看,这看起来像一个分数1/4。然而,在CSS中,斜线字符不用于分割,而是用于分隔一组值。在这种情况下,它允许我们在单个声明中设置开始列和结束列。

这实质上是对此的简写:

.child {
  grid-column-start: 1;
  grid-column-end: 4;
}

这里有一个狡猾的陷阱:我们提供的数字是基于列线,而不是列索引。

用图表最容易理解这个陷阱:

容易令人困惑的是,一个4列的网格实际上有5条列线。当我们为网格分配一个子元素时,我们使用这些线来锚定它们。如果我们想让我们的子元素跨越前3列,它需要从第1个列线开始,到第4个列线结束。

负数的列线

是否将字体、图片等二进制文件放入Git仓库进行版本管理?

在项目开发中,是否将字体文件、图片文件等二进制文件放入 Git 仓库进行版本管理,主要取决于项目的需求和团队的工作流程。以下是一些常见的考虑因素:

1. 版本管理

文本文件(如 HTML、CSS、JavaScript 文件)通常是较小的文件,并且可以清晰地显示差异(diff)。这些文件在 Git 中的管理非常有效,特别是当多人协作时,Git 可以轻松地比较文件的不同版本、合并更改。

二进制文件(如字体文件、图片、音频、视频等)由于它们的特殊格式,Git 无法像文本文件一样处理它们的差异(diff)。Git 只能在二进制级别进行版本管理,这意味着它无法显示更改的细节,只能存储文件的完整副本。

2. 考虑因素

  • 文件大小:二进制文件(特别是图片和字体文件)的文件大小通常比较大。如果将这些文件直接放入 Git 仓库,会导致仓库的体积迅速增加,尤其是如果你有很多版本的图片或字体文件时,Git 会保存每个版本的完整文件副本,这会显著增加仓库的大小。
  • 是否频繁的修改:如果二进制文件经常修改,例如图片或字体的替换,那么它们的版本管理可能变得非常低效,因为 Git 无法存储“差异”而是存储整个文件。如果有大量的二进制文件频繁修改,Git 仓库会迅速膨胀。
  • 性能问题:随着仓库中二进制文件的增加,Git 的性能可能会受到影响,尤其是在进行 git clone、git pull 和其他操作时,文件大小的增长会增加操作的时间和存储需求。

3. 最佳实践

方法一,使用 Git LFS(Git Large File Storage)

如果必须在 Git 仓库中管理二进制文件(如图片、字体等),可以使用 Git LFS。Git LFS 允许你将大文件(例如图片、音频、视频等)存储在专门的存储服务器上,并在 Git 仓库中仅存储指向这些文件的引用。这样可以避免仓库体积过大,提高 Git 操作的性能。

示例:

git lfs install
git lfs track "*.jpg"
git lfs track "*.png"
git lfs track "*.woff"

方法二,将大文件存储在外部服务器或 CDN

对于大图片和字体文件,可以将它们存储在外部服务器、内容分发网络(CDN)或专门的文件存储服务(如 Amazon S3)中,而不是直接存储在 Git 仓库中。然后在前端项目中通过 URL 引用它们。这样,Git 仓库只需管理轻量级的文件(如配置文件或链接文件),而不需要直接存储这些大的二进制文件。

方法三,避免频繁更新二进制文件

如果你的团队在开发过程中不需要频繁更改字体和图片文件,或者这些文件的更改非常有限,放入 Git 仓库中进行版本管理是可以的。但如果这些文件经常被修改,考虑使用 Git LFS 或其他外部存储方案。

4. 总结

  • 可以放入 Git 仓库的情况:如果二进制文件的变化较少,且文件较小,放入 Git 仓库中进行版本管理是可以的,特别是对于项目中使用的字体文件和小图标等。
  • 应避免直接放入 Git 仓库的情况:如果二进制文件较大或频繁修改,最好使用 Git LFS 或将文件存储在外部存储服务中,以避免 Git 仓库的体积迅速膨胀和性能问题。

设置Git使用UTF-8编码

运行git status命令,输出如下信息:

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        "m/\345\210\244\346\226\255\347\224\250\346\210\267\345\256\242\346\210\267\347\253\257\346\265\217\350\247\210\345\231\250\350\256\276\345\244\207\347\232\204\347\261\273\345\236\213/"
        "m/\350\247\206\345\217\243/"

说明git不能正常显示中文目录的名字,这个问题通常是由于Git的输出字符编码与终端的编码不匹配导致的。为了解决Git在输出中文目录名称时无法正确显示的问题,你可以通过以下几步进行配置:

1. 设置Git使用UTF-8编码

确保Git提交时使用UTF-8编码:

git config --global i18n.commitencoding utf-8

确保Git输出日志时使用UTF-8编码:

git config --global i18n.logoutputencoding utf-8

关闭路径的引用(即不使用\转义路径中的特殊字符),使路径直接显示:

git config --global core.quotepath off

2. 配置终端编码使用UTF-8编码

如果你使用的是Linux或macOS系统,确保终端的编码设置为UTF-8。你可以检查终端的当前编码,运行以下命令:

echo $LANG

如果输出不是UTF-8,你可以设置终端使用UTF-8编码。修改你的终端配置文件(例如.bashrc或.zshrc),加入以下内容:

export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

然后重新加载配置文件:

source ~/.bashrc  # 或者 source ~/.zshrc

3. 确保文件系统支持中文字符

确认你所在的文件系统支持中文字符。大多数现代文件系统(如ext4)都支持UTF-8编码,如果你在不同的文件系统上工作,确保它支持中文路径。

4. 重新运行git status

在配置完成之后,重新运行git status,应该能够正确显示中文目录和文件名。

设备像素比(device pixel ratio, DPR)、设备的逻辑宽度和物理宽度、CSS像素(逻辑像素)和物理像素

设置了width=device-width后,iPhone 7 Plus的浏览器执行alert(document.body.clientWidth);显示的值是398,但是iPhone 7 Plus屏幕的分辨率是1920 x 1080像素分辨率,为什么不是显示1920呢?

当你在 iPhone 7 Plus 上使用 width=device-width 并执行 alert(document.body.clientWidth) 显示值为 398 时,这个值并不是显示的设备屏幕分辨率(1920 x 1080 像素),而是与设备的物理像素密度设备像素比(device pixel ratio相关的值。

设备像素比(device pixel ratio, DPR

iPhone 7 Plus的屏幕分辨率为1920 x 1080像素,但它的设备像素比(DPR)为3。这意味着每个CSS像素(即网页设计时的逻辑像素)实际上由3个物理像素组成。例如,屏幕上实际的1 CSS像素会占用3 x 3 = 9物理像素。

width=device-width的作用

当你设置width=device-width时,浏览器会将视口的宽度设为设备的逻辑宽度,而不是真正的物理屏幕分辨率。

对于iPhone 7 Plus,视口宽度通常会设置为375px(iPhone 7 Plus设备的逻辑宽度)。这意味着你看到的document.body.clientWidth是375px,而不是1920px。

为什么会显示为398px?可能是因为浏览器在处理视口的宽度时考虑到了页面的边距、缩放因子或者其它因素。此外,浏览器还可能通过屏幕的设备像素比来进行相应的调整,从而显示为398px,而不是375px。这个值也可能受浏览器界面、工具栏或状态栏的影响。

判断用户客户端浏览器设备的类型

方法一,在客户端浏览器中使用js代码判断

借助navigator对象:

  • navigator.userAgent浏览器信息
  • navigator.appName浏览器版本名称
  • navigator.appVersion浏览器版本号
  • navigator.language浏览器语言
  • navigator.platform浏览器平台

示例代码如下:

<script type="text/javascript">
console.log('浏览器信息:');
console.log(navigator.userAgent);
console.log('浏览器版本名称:');
console.log(navigator.appName);
console.log('浏览器版本号:');
console.log(navigator.appVersion);
console.log('浏览器语言:');
console.log(navigator.language);
console.log('浏览器平台:');
console.log(navigator.platform);

// 从navigator.userAgent即可判断用户客户端浏览器设备的类型
// test()方法用于检测一个字符串中是否匹配某个正则模式,以下代码的功能是当用户客户端设备的类型匹配Android或webOS或iPhone或iPod或BlackBerry时,就跳转到移动端m站,否则跳转到PC端网站
window.location.href=/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)?"phone.html":"pc.html";
</script>

方法二,在服务器端使用nginx判断

根据用户设备不同返回不同样式的站点,以前经常使用的是纯前端的自适应布局,但无论是复杂性和易用性上面还是不如分开编写的好,比如我们常见的淘宝、京东……这些大型网站就都没有采用自适应,而是用分开制作的方式,根据用户请求的 user-agent 来判断是返回 PC站点还是移动端站点。

首先在 /usr/share/nginx/html 文件夹下 mkdir 分别新建两个文件夹 PC 和 mobile,vim 编辑两个 index.html 随便写点内容。

cd /usr/share/nginx/html
mkdir pc mobile
cd pc
vim index.html   # 随便写点比如 hello pc!
cd ../mobile
vim index.html   # 随便写点比如 hello mobile!

然后和设置二级域名虚拟主机时候一样,去 /etc/nginx/conf.d 文件夹下新建一个配置文件 fe.sherlocked93.club.conf:

# /etc/nginx/conf.d/fe.sherlocked93.club.conf

server {
  listen 80;
server_name fe.sherlocked93.club;

location / {
root  /usr/share/nginx/html/pc;
    if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
      root /usr/share/nginx/html/mobile;
    }
index index.html;
}
}

使用 $http_user_agent 全局变量来判断用户请求数据中的的user-agent,指向不同的root路径,返回对应站点。

参考

《你不知道的Nginx(万字详解)》

方法三,在服务器端使用编程来判断

例如,如果你使用PHP作为服务器端开发语言,那么可以Jenssegers/Agent包来判断客户端设备的类型。

CSS Global Initial Styles

Setting CSS global initial styles is mainly for ensuring compatibility across different browsers. Here’s an example:

/* Global Initial Styles */
html, body, div, span, h1, h2, h3, h4, h5, h6, a, em, img, p, dd, dl, dt, ul, li, ol, form, label, table, tr, td, input {
    margin: 0;
    padding: 0;
    color: #333;
}
p {
    font-size: 14px;
}
body {
    width: 100%;
    font-size: 12px;
    font-family: "Microsoft YaHei", Arial, Helvetica, serif;
    background-color: #f5f4f9;
}
a, a:link, a:visited {
    text-decoration: none;
}
a:hover {
    color: #e60012;
}
li {
    list-style: none;
}
img {
    border: none;
}
.clear {
    clear: both;
}

If you’re using CSS frameworks like Bootstrap, LayUI, or Tailwind CSS, they’ve already set these global initial styles for you, so you don’t need to set them yourself.